first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
+627
@@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <arch/arm/assembler.h>
|
||||
|
||||
.text
|
||||
|
||||
#define ALL_ROUTINES 1
|
||||
|
||||
// Define isb as a nop for older architectures
|
||||
#if !ARCH_ARMv7
|
||||
#define isb nop
|
||||
#define dsb nop
|
||||
#endif /* ! ARCH_ARMv7 */
|
||||
|
||||
ARM_FUNCTION _arm_read_cpsr
|
||||
|
||||
mrs r0, cpsr
|
||||
bx lr
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_main_id
|
||||
|
||||
mrc p15, 0, r0, c0, c0, 0
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_cache_id
|
||||
|
||||
mrc p15, 0, r0, c0, c0, 1
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_cache_level_id
|
||||
|
||||
mrc p15, 1, r0, c0, c0, 1
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_cache_size_selection
|
||||
|
||||
mrc p15, 2, r0, c0, c0, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_cache_size_selection
|
||||
|
||||
mcr p15, 2, r0, c0, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_cache_size_id
|
||||
|
||||
mrc p15, 1, r0, c0, c0, 0
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_extended_feature_regs
|
||||
|
||||
mov r12, r0
|
||||
mrc p15, 0, r0, c0, c1, 0
|
||||
mrc p15, 0, r1, c0, c1, 1
|
||||
mrc p15, 0, r2, c0, c1, 2
|
||||
mrc p15, 0, r3, c0, c1, 3
|
||||
stmia r12!, { r0-r3 }
|
||||
mrc p15, 0, r0, c0, c1, 4
|
||||
mrc p15, 0, r1, c0, c1, 5
|
||||
mrc p15, 0, r2, c0, c1, 6
|
||||
mrc p15, 0, r3, c0, c1, 7
|
||||
stmia r12!, { r0-r3 }
|
||||
mrc p15, 0, r0, c0, c2, 0
|
||||
mrc p15, 0, r1, c0, c2, 1
|
||||
mrc p15, 0, r2, c0, c2, 2
|
||||
mrc p15, 0, r3, c0, c2, 3
|
||||
stmia r12!, { r0-r3 }
|
||||
mrc p15, 0, r0, c0, c2, 4
|
||||
mrc p15, 0, r1, c0, c2, 5
|
||||
mrc p15, 0, r2, c0, c2, 6
|
||||
mrc p15, 0, r3, c0, c2, 7
|
||||
stmia r12, { r0-r3 }
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_memory_model_feature_regs
|
||||
|
||||
mov r12, r0
|
||||
mrc p15, 0, r0, c0, c1, 4
|
||||
mrc p15, 0, r1, c0, c1, 5
|
||||
mrc p15, 0, r2, c0, c1, 6
|
||||
mrc p15, 0, r3, c0, c1, 7
|
||||
stmia r12, { r0-r3 }
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_instruction_set_attribute_regs
|
||||
|
||||
mov r12, r0
|
||||
mrc p15, 0, r0, c0, c2, 0
|
||||
mrc p15, 0, r1, c0, c2, 1
|
||||
mrc p15, 0, r2, c0, c2, 2
|
||||
mrc p15, 0, r3, c0, c2, 3
|
||||
stmia r12!, { r0-r3 }
|
||||
mrc p15, 0, r0, c0, c2, 4
|
||||
mrc p15, 0, r1, c0, c2, 5
|
||||
stmia r12!, { r0-r1 }
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
ARM_FUNCTION _arm_read_cr
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_cr
|
||||
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_aux_cr
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 1
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_aux_cr
|
||||
|
||||
mcr p15, 0, r0, c1, c0, 1
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_dar
|
||||
|
||||
mcr p15, 0, r0, c3, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_ttb
|
||||
|
||||
mcr p15, 0, r0, c2, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_ttbcr
|
||||
|
||||
mcr p15, 0, r0, c2, c0, 2
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_ifsr
|
||||
|
||||
mrc p15, 0, r0, c5, c0, 1
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_dfsr
|
||||
|
||||
mrc p15, 0, r0, c5, c0, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_ifar
|
||||
|
||||
#if ARCH_ARMv7
|
||||
mrc p15, 0, r0, c6, c0, 2
|
||||
bx lr
|
||||
#endif
|
||||
ARM_FUNCTION _arm_read_dfar
|
||||
|
||||
mrc p15, 0, r0, c6, c0, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_cp_access_cr
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 2
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_cp_access_cr
|
||||
|
||||
mcr p15, 0, r0, c1, c0, 2
|
||||
isb
|
||||
bx lr
|
||||
|
||||
#if WITH_VFP
|
||||
ARM_FUNCTION _arm_read_fpexc
|
||||
|
||||
vmrs r0, fpexc
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_fpexc
|
||||
|
||||
vmsr fpexc, r0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_fpscr
|
||||
|
||||
vmrs r0, fpscr
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_fpscr
|
||||
|
||||
vmsr fpscr, r0
|
||||
bx lr
|
||||
|
||||
// Reset core registers to a known value. Kingfisher doesnt
|
||||
// do this on reset, and simulation traces will show 'x'
|
||||
// uninitialized values otherwise. Prefer deterministic
|
||||
ARM_FUNCTION _arm_init_fp_regs
|
||||
|
||||
vmov.i64 q0, #0
|
||||
vmov q1, q0
|
||||
vmov q2, q0
|
||||
vmov q3, q0
|
||||
vmov q4, q0
|
||||
vmov q5, q0
|
||||
vmov q6, q0
|
||||
vmov q7, q0
|
||||
#if FP_REGISTER_COUNT > 16
|
||||
vmov q8, q0
|
||||
vmov q9, q0
|
||||
vmov q10, q0
|
||||
vmov q11, q0
|
||||
vmov q12, q0
|
||||
vmov q13, q0
|
||||
vmov q14, q0
|
||||
vmov q15, q0
|
||||
#endif
|
||||
bx lr
|
||||
|
||||
#endif
|
||||
|
||||
#if ARCH_ARMv7
|
||||
ARM_FUNCTION _arm_read_l2_aux_cr
|
||||
|
||||
mrc p15, 1, r0, c9, c0, 2
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_l2_aux_cr
|
||||
|
||||
mcr p15, 1, r0, c9, c0, 2
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_pmreg
|
||||
|
||||
cmp r0, #0
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 0
|
||||
b 2f
|
||||
1: cmp r0, #1
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 1
|
||||
b 2f
|
||||
1: cmp r0, #2
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 2
|
||||
b 2f
|
||||
1: cmp r0, #3
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 3
|
||||
b 2f
|
||||
1: cmp r0, #4
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 4
|
||||
b 2f
|
||||
1: cmp r0, #5
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c12, 5
|
||||
b 2f
|
||||
1: cmp r0, #6
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c13, 0
|
||||
b 2f
|
||||
1: cmp r0, #7
|
||||
bne 1f
|
||||
mrc p15, 0, r0, c9, c13, 1
|
||||
b 2f
|
||||
1: cmp r0, #8
|
||||
bne 2f
|
||||
mrc p15, 0, r0, c9, c13, 2
|
||||
b 2f
|
||||
1: cmp r0, #9
|
||||
bne 2f
|
||||
mcr p15, 0, r0, c9, c14, 0
|
||||
b 2f
|
||||
1: cmp r0, #10
|
||||
bne 2f
|
||||
mcr p15, 0, r0, c9, c14, 1
|
||||
b 2f
|
||||
1: cmp r0, #11
|
||||
bne 2f
|
||||
mcr p15, 0, r0, c9, c14, 2
|
||||
2: isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_pmreg
|
||||
|
||||
cmp r0, #0
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 0
|
||||
b 2f
|
||||
1: cmp r0, #1
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 1
|
||||
b 2f
|
||||
1: cmp r0, #2
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 2
|
||||
b 2f
|
||||
1: cmp r0, #3
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 3
|
||||
b 2f
|
||||
1: cmp r0, #4
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 4
|
||||
b 2f
|
||||
1: cmp r0, #5
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c12, 5
|
||||
b 2f
|
||||
1: cmp r0, #6
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c13, 0
|
||||
b 2f
|
||||
1: cmp r0, #7
|
||||
bne 1f
|
||||
mcr p15, 0, r1, c9, c13, 1
|
||||
b 2f
|
||||
1: cmp r0, #8
|
||||
bne 2f
|
||||
mcr p15, 0, r1, c9, c13, 2
|
||||
b 2f
|
||||
1: cmp r0, #9
|
||||
bne 2f
|
||||
mcr p15, 0, r1, c9, c14, 0
|
||||
b 2f
|
||||
1: cmp r0, #10
|
||||
bne 2f
|
||||
mcr p15, 0, r1, c9, c14, 1
|
||||
b 2f
|
||||
1: cmp r0, #11
|
||||
bne 2f
|
||||
mcr p15, 0, r1, c9, c14, 2
|
||||
2: isb
|
||||
bx lr
|
||||
#endif /* ARCH_ARMv7 */
|
||||
|
||||
#if ALL_ROUTINES
|
||||
ARM_FUNCTION _arm_read_user_rw_tid
|
||||
|
||||
mrc p15, 0, r0, c13, c0, 2
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_user_rw_tid
|
||||
|
||||
mcr p15, 0, r0, c13, c0, 2
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_user_ro_tid
|
||||
|
||||
mrc p15, 0, r0, c13, c0, 3
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_user_ro_tid
|
||||
|
||||
mcr p15, 0, r0, c13, c0, 3
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_read_sup_tid
|
||||
|
||||
mrc p15, 0, r0, c13, c0, 4
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_sup_tid
|
||||
|
||||
mcr p15, 0, r0, c13, c0, 4
|
||||
isb
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
ARM_FUNCTION _arm_read_perip_port_remap
|
||||
|
||||
mrc p15, 0, r0, c15, c2, 4
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_perip_port_remap
|
||||
|
||||
mcr p15, 0, r0, c15, c2, 4
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_flush_tlbs
|
||||
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c8, c7, 0
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
|
||||
#define EXT(x) _ ## x
|
||||
|
||||
#if ALL_ROUTINES
|
||||
/* mpu routines */
|
||||
#define WRITE_DATA_PROT_REGION(func, n) \
|
||||
.global EXT(func); \
|
||||
EXT(func): \
|
||||
mcr p15, 0, r0, c6, c##n, 0; \
|
||||
isb
|
||||
bx lr
|
||||
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_0, 0)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_1, 1)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_2, 2)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_3, 3)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_4, 4)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_5, 5)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_6, 6)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_7, 7)
|
||||
WRITE_DATA_PROT_REGION(arm_write_dprot_region_8, 8)
|
||||
|
||||
#define WRITE_INSTRUCTION_PROT_REGION(func, n) \
|
||||
.global EXT(func); \
|
||||
EXT(func): \
|
||||
mcr p15, 0, r0, c6, c##n, 1; \
|
||||
isb
|
||||
bx lr
|
||||
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_0, 0)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_1, 1)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_2, 2)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_3, 3)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_4, 4)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_5, 5)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_6, 6)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_7, 7)
|
||||
WRITE_INSTRUCTION_PROT_REGION(arm_write_iprot_region_8, 8)
|
||||
|
||||
.global _arm_write_data_prot_register
|
||||
_arm_write_data_prot_register:
|
||||
mcr p15, 0, r0, c5, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
.global _arm_write_ins_prot_register
|
||||
_arm_write_ins_prot_register:
|
||||
mcr p15, 0, r0, c5, c0, 1
|
||||
isb
|
||||
bx lr
|
||||
|
||||
.global _arm_write_cacheable_registers
|
||||
_arm_write_cacheable_registers:
|
||||
mcr p15, 0, r0, c2, c0, 0
|
||||
mcr p15, 0, r1, c2, c0, 1
|
||||
isb
|
||||
bx lr
|
||||
|
||||
.global _arm_write_bufferable_register
|
||||
_arm_write_bufferable_register:
|
||||
mcr p15, 0, r0, c3, c0, 0
|
||||
isb
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
/* uint arch_enable_ints(void); */
|
||||
ARM_FUNCTION _arch_enable_ints
|
||||
|
||||
mrs r0, cpsr
|
||||
bic r1, r0, #(1<<7)
|
||||
#if WITH_FIQ_TIMER
|
||||
bic r1, r1, #(1<<6)
|
||||
#endif
|
||||
msr cpsr_c, r1
|
||||
and r0, r0, #(1<<7)
|
||||
bx lr
|
||||
|
||||
/* uint arch_disable_ints(void); */
|
||||
ARM_FUNCTION _arch_disable_ints
|
||||
|
||||
mrs r0, cpsr
|
||||
orr r1, r0, #(1<<7)
|
||||
#if WITH_FIQ_TIMER
|
||||
orr r1, r1, #(1<<6)
|
||||
#endif
|
||||
msr cpsr_c, r1
|
||||
and r0, r0, #(1<<7)
|
||||
bx lr
|
||||
|
||||
/* uint arch_restore_ints(uint state); */
|
||||
ARM_FUNCTION _arch_restore_ints
|
||||
|
||||
mrs r1, cpsr
|
||||
and r0, r0, #(1<<7)
|
||||
bic r1, r1, #(1<<7)
|
||||
orr r2, r1, r0
|
||||
msr cpsr_c, r2
|
||||
and r0, r1, #(1<<7)
|
||||
bx lr
|
||||
|
||||
/* void arm_enable_fiqs(void); */
|
||||
ARM_FUNCTION _arm_enable_fiqs
|
||||
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #(1<<6)
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
|
||||
/* void arm_disable_fiqs(void); */
|
||||
ARM_FUNCTION _arm_disable_fiqs
|
||||
|
||||
mrs r0, cpsr
|
||||
orr r0, r0, #(1<<6)
|
||||
msr cpsr_c, r0
|
||||
bx lr
|
||||
|
||||
#if ARCH_ARMv7
|
||||
ARM_FUNCTION _arm_read_vbar
|
||||
|
||||
mrc p15, 0, r0, c12, c0, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_write_vbar
|
||||
|
||||
mcr p15,0, r0, c12, c0, 0
|
||||
bx lr
|
||||
|
||||
#endif
|
||||
|
||||
#if ARCH_ARMv7
|
||||
ARM_FUNCTION _arm_flush_branch_predictor
|
||||
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 6 /* flush the branch predictor cache */
|
||||
isb
|
||||
mov pc, lr
|
||||
#endif
|
||||
|
||||
/* void arm_memory_barrier(void); */
|
||||
ARM_FUNCTION _arm_memory_barrier
|
||||
|
||||
#if ARCH_ARMv7
|
||||
dmb
|
||||
#endif
|
||||
bx lr
|
||||
|
||||
#ifdef PRODUCT_EMBEDDEDIOP
|
||||
/* <rdar://problem/16290859> WFI errata workaround for Cortex-A5 */
|
||||
dummy_store:
|
||||
.long 0xaaaabbbb
|
||||
|
||||
.balign 32
|
||||
#endif //PRODUCT_EMBEDDEDIOP
|
||||
|
||||
ARM_FUNCTION _arch_halt
|
||||
|
||||
#if !NO_ARM_HALT
|
||||
# if ARCH_ARMv7
|
||||
dsb
|
||||
#ifdef PRODUCT_EMBEDDEDIOP
|
||||
str r0, dummy_store
|
||||
#endif //PRODUCT_EMBEDDEDIOP
|
||||
wfi
|
||||
# else
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */
|
||||
# endif
|
||||
#endif
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arch_spin
|
||||
|
||||
#if ARCH_ARMv7 || ARCH_ARMv8
|
||||
wfe
|
||||
#endif
|
||||
b _arch_spin
|
||||
|
||||
#if WITH_ARM_DCC
|
||||
ARM_FUNCTION _read_dtr
|
||||
|
||||
mrc p14, 0, r0, c0, c5, 0
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _write_dtr
|
||||
|
||||
mcr p14, 0, r0, c0, c5, 0
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _read_dscr
|
||||
|
||||
mrc p14, 0, r0, c0, c1, 0
|
||||
bx lr
|
||||
#endif /* WITH_ARM_DCC */
|
||||
|
||||
|
||||
#if CPU_APPLE_SWIFT
|
||||
ARM_FUNCTION _swift_read_l2cerrsts
|
||||
|
||||
mrc p15, 1, r0, c15, c2, 5
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _swift_write_l2cerrsts
|
||||
|
||||
mcr p15, 1, r0, c15, c2, 5
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _swift_read_l2cerradr
|
||||
|
||||
mrc p15, 1, r0, c15, c2, 7
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _swift_write_l2cerradr
|
||||
|
||||
mcr p15, 1, r0, c15, c2, 7
|
||||
isb
|
||||
bx lr
|
||||
#endif /* CPU_APPLE_SWIFT */
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2010 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <arch/arm/assembler.h>
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* Cache functions for ARM v7
|
||||
*/
|
||||
|
||||
/* perform loop unrolling to optimize for multi-line operations rdar://problem/6722268 */
|
||||
ARM_FUNCTION _arm_clean_dcache_line_8
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_7
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_6
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_5
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_4
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_3
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line_2
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache_line
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 1 // clean L1/L2 line by MVA
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
/* perform loop unrolling to optimize for multi-line operations rdar://problem/6722268 */
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_8
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_7
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_6
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_5
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_4
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_3
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line_2
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache_line
|
||||
|
||||
mcr p15, 0, r0, c7, c6, 1 // invalidate L1/L2 line by MVA
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
/* perform loop unrolling to optimize for multi-line operations rdar://problem/6722268 */
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_8
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_7
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_6
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_5
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_4
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_3
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line_2
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
add r0, r0, #(CPU_CACHELINE_SIZE)
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache_line
|
||||
|
||||
mcr p15, 0, r0, c7, c14, 1 // clean/invalidate L1/L2 line by MVA
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
|
||||
ARM_FUNCTION _arm_clean_dcache
|
||||
|
||||
mov r2, #((1 << CPU_CACHEINDEX_SHIFT) << CPU_CACHELINE_SHIFT)
|
||||
1:
|
||||
sub r2, r2, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mov r1, #((1 << CPU_CACHESET_SHIFT) << (32-CPU_CACHESET_SHIFT))
|
||||
2:
|
||||
subs r1, r1, #(1 << (32-CPU_CACHESET_SHIFT))
|
||||
orr r0, r1, r2
|
||||
mcr p15, 0, r0, c7, c10, 2 // clean one line by way and set
|
||||
bne 2b
|
||||
cmp r2, #0
|
||||
bne 1b
|
||||
|
||||
#if L2_CACHE_SIZE
|
||||
mov r2, #((1 << L2_CACHE_SETS) << 6)
|
||||
1:
|
||||
sub r2, r2, #(1 << 6)
|
||||
mov r1, #((1 << 3) << 29)
|
||||
2:
|
||||
subs r1, r1, #(1 << 29)
|
||||
orr r0, r1, r2
|
||||
orr r0, r0, #(1 << 1)
|
||||
mcr p15, 0, r0, c7, c10, 2 // clean one line by way and set
|
||||
bne 2b
|
||||
cmp r2, #0
|
||||
bne 1b
|
||||
#endif
|
||||
|
||||
mov r0, #0
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_clean_invalidate_dcache
|
||||
|
||||
mov r2, #((1 << CPU_CACHEINDEX_SHIFT) << CPU_CACHELINE_SHIFT)
|
||||
1:
|
||||
sub r2, r2, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mov r1, #((1 << CPU_CACHESET_SHIFT) << (32-CPU_CACHESET_SHIFT))
|
||||
2:
|
||||
subs r1, r1, #(1 << (32-CPU_CACHESET_SHIFT))
|
||||
orr r0, r1, r2
|
||||
mcr p15, 0, r0, c7, c14, 2 // clean and invalidate one line by way and set
|
||||
bne 2b
|
||||
cmp r2, #0
|
||||
bne 1b
|
||||
|
||||
#if L2_CACHE_SIZE
|
||||
mov r2, #((1 << L2_CACHE_SETS) << 6)
|
||||
1:
|
||||
sub r2, r2, #(1 << 6)
|
||||
mov r1, #((1 << 3) << 29)
|
||||
2:
|
||||
subs r1, r1, #(1 << 29)
|
||||
orr r0, r1, r2
|
||||
orr r0, r0, #(1 << 1)
|
||||
mcr p15, 0, r0, c7, c14, 2 // clean and invalidate one line by way and set
|
||||
bne 2b
|
||||
cmp r2, #0
|
||||
bne 1b
|
||||
#endif
|
||||
|
||||
mov r0, #0
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_dcache
|
||||
|
||||
// This is a fancy way of writing "0". Thr first sub will make this (1<<CPU_CACHESET_SHIFT)-1
|
||||
mov r1, #((1 << CPU_CACHESET_SHIFT) << (32-CPU_CACHESET_SHIFT))
|
||||
mov r2, #((1 << CPU_CACHEINDEX_SHIFT) << CPU_CACHELINE_SHIFT)
|
||||
1:
|
||||
sub r1, r1, #(1 << (32-CPU_CACHESET_SHIFT))
|
||||
orr r0, r1, r2
|
||||
2:
|
||||
#if (1 << CPU_CACHEINDEX_SHIFT) < 16
|
||||
#error "Not enough cache sets for unroll in _arm_invalidate_dcache"
|
||||
#endif
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
sub r0, r0, #(1 << CPU_CACHELINE_SHIFT)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
cmp r0, r1
|
||||
bne 2b
|
||||
cmp r1, #0
|
||||
bne 1b
|
||||
|
||||
#if L2_CACHE_SIZE
|
||||
mov r2, #((1 << L2_CACHE_SETS) << 6)
|
||||
1:
|
||||
sub r2, r2, #(1 << 6)
|
||||
mov r1, #((1 << 3) << 29)
|
||||
2:
|
||||
subs r1, r1, #(1 << 29)
|
||||
orr r0, r1, r2
|
||||
orr r0, r0, #(1 << 1)
|
||||
mcr p15, 0, r0, c7, c6, 2 // invalidate one line by way and set
|
||||
bne 2b
|
||||
cmp r2, #0
|
||||
bne 1b
|
||||
#endif
|
||||
|
||||
dmb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_invalidate_icache
|
||||
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache + btb (if supported) */
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
|
||||
ARM_FUNCTION _arm_clean_caches
|
||||
|
||||
stmfd sp!, {lr}
|
||||
|
||||
bl _arm_clean_dcache
|
||||
bl _arm_invalidate_icache
|
||||
|
||||
ldmfd sp!, {lr}
|
||||
bx lr
|
||||
|
||||
#if WITH_L1_PARITY
|
||||
ARM_FUNCTION _arm_enable_l1parity
|
||||
|
||||
mrc p15, 0, r0, c1, c0, 1
|
||||
#if CPU_ARM_CORTEX_A8
|
||||
orr r0, r0, #(1 << 3) // set the L1PE bit
|
||||
#elif CPU_ARM_CORTEX_A5
|
||||
orr r0, r0, #(1 << 9) // set the "parity on" bit
|
||||
#endif
|
||||
mcr p15, 0, r0, c1, c0, 1
|
||||
isb
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
ARM_FUNCTION _arm_drain_write_buffer
|
||||
|
||||
mov r0, #0
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
#include <debug.h>
|
||||
#include <sys/menu.h>
|
||||
#include <arch/arm/arm.h>
|
||||
|
||||
void arm_l1cache_dump(int dcache, unsigned int mva)
|
||||
{
|
||||
register unsigned index = (mva >> 6) & 0x7f;
|
||||
unsigned way, addr, word, data0, data1;
|
||||
unsigned tag, i, parity, tmp;
|
||||
unsigned lookup;
|
||||
unsigned cr = arm_read_cr();
|
||||
|
||||
arm_write_cr(cr & ~((1 << 12) | (1 << 2)));
|
||||
lookup = (mva != -1UL);
|
||||
for (way=0; way<4; way++) {
|
||||
if (!lookup) index = 0;
|
||||
do {
|
||||
addr = (way << 30) | (index << 6);
|
||||
if (dcache) {
|
||||
__asm__ volatile("mcr p15,0,%0,c15,c2,6" ::"r"(addr));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c0,0" :"=r"(tag));
|
||||
} else {
|
||||
__asm__ volatile("mcr p15,0,%0,c15,c3,6" ::"r"(addr));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c1,0" :"=r"(tag));
|
||||
}
|
||||
tag <<= 12;
|
||||
for (word = 0; word < 16; word++) {
|
||||
addr = (way << 30) | (index << 6) | (word << 2);
|
||||
if (dcache) {
|
||||
__asm__ volatile("mcr p15,0,%0,c15,c2,7" ::"r"(addr));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c0,0" :"=r"(data0));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c0,1" :"=r"(data1));
|
||||
} else {
|
||||
__asm__ volatile("mcr p15,0,%0,c15,c3,7" ::"r"(addr));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c1,0" :"=r"(data0));
|
||||
__asm__ volatile("mrc p15,0,%0,c15,c1,1" :"=r"(data1));
|
||||
}
|
||||
if (word == 0)
|
||||
printf("PA %08x: %c ", tag | ((index & 0x3f) << 6),
|
||||
dcache && (data1&1) ? 'D':' ');
|
||||
parity = 0;
|
||||
tmp = data0;
|
||||
for (i=0; i<8; i++) {
|
||||
parity ^= tmp & 0x01010101;
|
||||
tmp >>= 1;
|
||||
}
|
||||
parity &= 0x01010101;
|
||||
parity = (parity >> 21) | (parity >> 14) | (parity >> 7) | parity;
|
||||
if ((parity ^ (data1 >> 2)) & 0xf)
|
||||
printf(" >%08x-%x<", data0, (data1>>2)&0xf);
|
||||
else
|
||||
printf(" %08x", data0);
|
||||
}
|
||||
printf("\n");
|
||||
} while (!lookup && (++index < 128));
|
||||
}
|
||||
arm_clean_dcache();
|
||||
arm_write_cr(cr);
|
||||
}
|
||||
|
||||
void dump_l1caches(int disable)
|
||||
{
|
||||
unsigned cr;
|
||||
|
||||
cr = arm_read_cr();
|
||||
|
||||
if (disable) {
|
||||
arm_write_cr(cr & ~((1<<12)|(1<<2)));
|
||||
arm_clean_dcache();
|
||||
}
|
||||
|
||||
arm_l1cache_dump(0, -1);
|
||||
arm_l1cache_dump(1, -1);
|
||||
|
||||
if (disable)
|
||||
arm_write_cr(cr);
|
||||
}
|
||||
|
||||
#if defined(WITH_MENU) && WITH_MENU
|
||||
static int do_l1dump(int argc, struct cmd_arg *args) { dump_l1caches(1); return 0; }
|
||||
MENU_COMMAND_DEVELOPMENT(l1dump, do_l1dump, "dump L1 i/d contents", NULL);
|
||||
#endif
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <arch/arm/arm.h>
|
||||
#include <arch/arch_task.h>
|
||||
#include <arch/arm/assembler.h>
|
||||
|
||||
/*
|
||||
* Task context switch support.
|
||||
*
|
||||
* Basic VFP/Neon floating point context switch only.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code here must remain synchronised with the structure and offsets defined in arch_task.h:
|
||||
*
|
||||
* struct arch_task {
|
||||
* uint32_t regs[10]; // r4-r11, r13, r14
|
||||
* #if WITH_VFP
|
||||
* uint32_t fpscr;
|
||||
* uint32_t fpexc;
|
||||
* uint32_t fpinst;
|
||||
* uint32_t fpinst2;
|
||||
* uint64_t fpregs[32]; // assume VFP-D32
|
||||
* #endif
|
||||
* };
|
||||
*/
|
||||
|
||||
/*
|
||||
* void arch_task_context_switch(struct arch_task *old, struct arch_task *new_task);
|
||||
*/
|
||||
|
||||
ARM_FUNCTION _arch_task_context_switch
|
||||
|
||||
/* save non-volatile core registers */
|
||||
stmia r0, { r4-r11, r13, r14 }
|
||||
|
||||
#if WITH_VFP
|
||||
#if !WITH_VFP_ALWAYS_ON
|
||||
/* save fpexc */
|
||||
vmrs r2, fpexc
|
||||
str r2, [r0, #ARM_ARCH_TASK_FPEXC]
|
||||
|
||||
/* check FP enable state */
|
||||
tst r2, #FPEXC_EN
|
||||
beq L_fp_save_done
|
||||
|
||||
/* save fpscr */
|
||||
vmrs r4, fpscr
|
||||
str r4, [r0, #ARM_ARCH_TASK_FPSCR]
|
||||
#endif
|
||||
|
||||
/* save the FP registers */
|
||||
add r3, r0, #ARM_ARCH_TASK_FPREGS
|
||||
vstm.64 r3!, { d0-d15 }
|
||||
#if FP_REGISTER_COUNT > 16
|
||||
vstm.64 r3, { d16-d31 }
|
||||
#endif
|
||||
L_fp_save_done:
|
||||
#endif /* WITH_VFP */
|
||||
|
||||
/* select the context we're going to switch to and invoke the context restore */
|
||||
mov r0, r1
|
||||
b _arch_task_context_restore
|
||||
|
||||
|
||||
/*
|
||||
* void arch_task_context_restore(struct arch_task *restore_context)
|
||||
*/
|
||||
|
||||
ARM_FUNCTION _arch_task_context_restore
|
||||
|
||||
#if WITH_VFP
|
||||
#if !WITH_VFP_ALWAYS_ON
|
||||
/* restore fpexc */
|
||||
ldr r2, [r0, #ARM_ARCH_TASK_FPEXC]
|
||||
vmsr fpexc, r2
|
||||
|
||||
/* check FP enable state */
|
||||
tst r2, #FPEXC_EN
|
||||
beq L_fp_restore_done
|
||||
|
||||
/* restore fpscr */
|
||||
ldr r4, [r0, #ARM_ARCH_TASK_FPSCR]
|
||||
vmsr fpscr, r4
|
||||
#endif
|
||||
|
||||
/* restore the FP registers */
|
||||
add r3, r0, #ARM_ARCH_TASK_FPREGS
|
||||
vldm.64 r3!, { d0-d15 }
|
||||
#if FP_REGISTER_COUNT > 16
|
||||
vldm.64 r3, { d16-d31 }
|
||||
#endif
|
||||
L_fp_restore_done:
|
||||
#endif /* WITH_VFP */
|
||||
|
||||
/* restore non-volatile core registers */
|
||||
ldmia r0, { r4-r11, r13, r14 }
|
||||
bx lr
|
||||
|
||||
|
||||
#if WITH_VFP && !WITH_VFP_ALWAYS_ON
|
||||
/*
|
||||
* void arm_call_fpsaved(void *arg, void (*func)(void *arg))
|
||||
*/
|
||||
.globl _arm_call_fpsaved
|
||||
_arm_call_fpsaved:
|
||||
stmfd sp!, {lr}
|
||||
|
||||
/* fetch fpexc and check FP enable state */
|
||||
vmrs r2, fpexc
|
||||
tst r2, #FPEXC_EN
|
||||
beq 1f /* bypass save if VFP is off */
|
||||
|
||||
/* save fpscr */
|
||||
vmrs r3, fpscr
|
||||
push {r3}
|
||||
|
||||
/* save the FP registers */
|
||||
#if FP_REGISTER_COUNT > 16
|
||||
vpush { d16-d31 }
|
||||
#endif
|
||||
vpush { d0-d15 }
|
||||
1:
|
||||
/* stack fpexc last, always guranteed to be on the stack */
|
||||
push {r2}
|
||||
|
||||
/* unconditionally enable VFP for this call */
|
||||
orr r2, r2, #FPEXC_EN
|
||||
vmsr fpexc, r2
|
||||
|
||||
/* branch to the routine */
|
||||
blx r1
|
||||
|
||||
/* pop fpexc and test whether FP was saved */
|
||||
pop {r2}
|
||||
tst r2, #FPEXC_EN
|
||||
beq 2f
|
||||
|
||||
/* restore the FP registers */
|
||||
vpop { d0-d15 }
|
||||
#if FP_REGISTER_COUNT > 16
|
||||
vpop { d16-d31 }
|
||||
#endif
|
||||
|
||||
/* restore fpcsr */
|
||||
pop {r3}
|
||||
vmsr fpscr, r2
|
||||
2:
|
||||
/* restore fpexc last, may disable VFP */
|
||||
vmsr fpexc, r2
|
||||
|
||||
ldmfd sp!, {lr}
|
||||
bx lr
|
||||
#endif /* WITH_VFP */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <arch/arm/arm.h>
|
||||
#include <lib/libc.h>
|
||||
#include <sys.h>
|
||||
#include <sys/menu.h>
|
||||
|
||||
#if defined(WITH_MENU) && WITH_MENU
|
||||
|
||||
extern char cortex_hang_start, cortex_hang_ffe, cortex_hang_end;
|
||||
typedef uint32_t (*hang_func_t)(uint32_t);
|
||||
static uint8_t *hang_buffer = NULL;
|
||||
static hang_func_t cortex_hang;
|
||||
|
||||
static int do_hang(int argc, struct cmd_arg *args)
|
||||
{
|
||||
u_int32_t count = 10000;
|
||||
utime_t before, after;
|
||||
int i, ret, always = 0;
|
||||
char *entry_point;
|
||||
|
||||
if (argc > 1)
|
||||
count = args[1].u;
|
||||
if (!strcmp(args[0].str, "hangloop"))
|
||||
always = 1;
|
||||
|
||||
if (hang_buffer == NULL) {
|
||||
hang_buffer = malloc(8192);
|
||||
entry_point = (char *)((((uint32_t)hang_buffer + 0xfff) & ~0xfff) -
|
||||
(&cortex_hang_ffe + 2 - &cortex_hang_start));
|
||||
memcpy(entry_point, &cortex_hang_start, &cortex_hang_end - &cortex_hang_start);
|
||||
arm_clean_dcache();
|
||||
arm_invalidate_icache();
|
||||
cortex_hang = (hang_func_t)(entry_point+1); /* Thumb */
|
||||
printf("Created hang code buffer; base = %p, entry = %p\n", hang_buffer, cortex_hang);
|
||||
}
|
||||
|
||||
for (i=0; (i<100) || always; i++) {
|
||||
printf("Try %3d: ", i+1);
|
||||
before = system_time();
|
||||
ret = cortex_hang(count);
|
||||
after = system_time();
|
||||
printf("complete; time = %6d\n", after-before);
|
||||
if (ret != 0) printf(" EARLY EXIT!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEBUG(hang, do_hang, "try to hang cortex", NULL);
|
||||
MENU_COMMAND_DEBUG(hangloop, do_hang, "try to hang cortex - run forever", NULL);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
.text
|
||||
.global _cortex_hang_start, _cortex_hang_ffe, _cortex_hang_end
|
||||
.thumb
|
||||
.syntax unified
|
||||
|
||||
// Believe it or not, without this, it does not fail
|
||||
#define NOP mov r8,r8
|
||||
|
||||
// R0 holds the number of iterations we should run
|
||||
// start this routine at a page boundary
|
||||
_cortex_hang_start:
|
||||
// save some registers and set aside a word
|
||||
push {r4,r5,r6,r7,lr}
|
||||
sub sp, #4
|
||||
1:
|
||||
cmp r0, #0
|
||||
beq 1f
|
||||
NOP // 0xff0
|
||||
NOP // 0xff2
|
||||
NOP // 0xff4
|
||||
NOP // 0xff6
|
||||
subs r0, #1 // 0xff8
|
||||
str.w ip, [sp] // 0xffa
|
||||
_cortex_hang_ffe:
|
||||
bl 1b // 0xffe
|
||||
1:
|
||||
add sp, #4
|
||||
pop {r4,r5,r6,r7,pc}
|
||||
bx lr
|
||||
_cortex_hang_end:
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include <arch/arm/arm.h>
|
||||
#include <debug.h>
|
||||
#include <platform.h>
|
||||
#include <platform/memmap.h>
|
||||
|
||||
#if PERIPH_PORT_REMAP
|
||||
static void config_periph_port_remap(void *base, size_t len);
|
||||
#endif
|
||||
|
||||
#if WITH_EARLY_ICACHE && WITH_L1_PARITY
|
||||
#error Early i-cache init and L1 parity enable are mutually exclusive
|
||||
#endif
|
||||
|
||||
int arch_cpu_init(bool resume)
|
||||
{
|
||||
u_int32_t cr, aux_cr;
|
||||
|
||||
aux_cr = 0;
|
||||
|
||||
#if WITH_CACHE
|
||||
/* make sure the cpu caches are invalidated */
|
||||
#if !WITH_EARLY_ICACHE
|
||||
/* d-cache init is deferred if we're turning i-cache on early */
|
||||
arm_invalidate_dcache();
|
||||
#endif
|
||||
arm_invalidate_icache();
|
||||
#endif
|
||||
|
||||
#if ARCH_ARMv7
|
||||
aux_cr = arm_read_aux_cr();
|
||||
|
||||
#if CPU_ARM_CORTEX_A8
|
||||
// Ask platform if WFI should be enabled or not
|
||||
if (platform_get_core_idle_enable()) {
|
||||
aux_cr &= ~(1 << 8);
|
||||
} else {
|
||||
aux_cr |= (1 << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_ARCHITECTED_L2
|
||||
/* Manage the v7 L2 cache */
|
||||
# if WITH_AUX_L2_ENABLE_BIT && L2_CACHE_SIZE
|
||||
aux_cr |= (1 << 1);
|
||||
# else
|
||||
aux_cr &= ~(1 << 1);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if SET_AUX_SMP_BIT
|
||||
/* Set SMP bit; enable snooping within cluster and sharing of L2 */
|
||||
aux_cr |= (1 << 6);
|
||||
#endif
|
||||
|
||||
arm_write_aux_cr(aux_cr);
|
||||
#endif
|
||||
|
||||
/* read control register default value */
|
||||
cr = arm_read_cr();
|
||||
|
||||
#if WITH_BRANCH_PREDICTION
|
||||
/* turn on branch predictor */
|
||||
cr |= (1 << 11);
|
||||
#endif
|
||||
|
||||
#if WITH_CACHE && WITH_EARLY_ICACHE
|
||||
/* early i-cache enable */
|
||||
cr |= (1 << 12);
|
||||
|
||||
arm_write_cr(cr);
|
||||
#endif
|
||||
|
||||
#if PERIPH_PORT_REMAP
|
||||
/* do any peripheral port remapping */
|
||||
config_periph_port_remap((void *)PERIPH_BASE, PERIPH_LEN);
|
||||
#endif
|
||||
|
||||
#if WITH_CACHE
|
||||
|
||||
#if WITH_EARLY_ICACHE
|
||||
/* d-cache invalidation delayed until this point */
|
||||
arm_invalidate_dcache();
|
||||
#else
|
||||
/* turn on i-cache */
|
||||
cr |= (1 << 12);
|
||||
#endif
|
||||
|
||||
/* turn on d-cache */
|
||||
cr |= (1 << 2);
|
||||
|
||||
#if WITH_L1_PARITY
|
||||
arm_enable_l1parity();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if WITH_UNALIGNED_MEM
|
||||
/* enable unaligned access handler */
|
||||
cr &= ~(1 << 1);
|
||||
#if !ARCH_ARMv7
|
||||
cr |= (1 << 22);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* enable the caches and etc. before setting up the translation table */
|
||||
arm_write_cr(cr);
|
||||
|
||||
#if WITH_MMU
|
||||
/* set up the translation table and then turn on the MMU */
|
||||
arm_mmu_init(resume);
|
||||
cr |= (1 << 0);
|
||||
|
||||
arm_write_cr(cr);
|
||||
#endif
|
||||
|
||||
#if WITH_VFP
|
||||
/* initialize VFP */
|
||||
arm_fp_init();
|
||||
#if WITH_VFP_ALWAYS_ON
|
||||
arm_fp_enable(true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_cpu_quiesce(void)
|
||||
{
|
||||
u_int32_t cr, aux_cr;
|
||||
|
||||
aux_cr = 0;
|
||||
|
||||
#if ARCH_ARMv7
|
||||
aux_cr = arm_read_aux_cr();
|
||||
|
||||
#if CPU_ARM_CORTEX_A8
|
||||
/* turn WFI on */
|
||||
aux_cr &= ~(1 << 8);
|
||||
#endif
|
||||
|
||||
arm_write_aux_cr(aux_cr);
|
||||
#endif
|
||||
|
||||
#if WITH_CACHE && !CLEAN_INV_CACHE_ON_QUIESCE
|
||||
/* clean the d-cache */
|
||||
arm_clean_dcache();
|
||||
#endif
|
||||
|
||||
/* read the control regiser base value */
|
||||
cr = arm_read_cr();
|
||||
|
||||
#if WITH_MMU
|
||||
/* turn off the mmu */
|
||||
cr &= ~(1 << 0);
|
||||
#endif
|
||||
#if WITH_CACHE
|
||||
/* turn off d-cache */
|
||||
cr &= ~(1 << 2);
|
||||
|
||||
/* turn off i-cache */
|
||||
cr &= ~(1 << 12);
|
||||
#endif
|
||||
|
||||
#if WITH_BRANCH_PREDICTION
|
||||
/* turn off branch predictor */
|
||||
cr &= ~(1 << 11);
|
||||
#endif
|
||||
|
||||
#if WITH_UNALIGNED_MEM
|
||||
/* disable unaligned access handler */
|
||||
cr |= (1 << 1);
|
||||
cr &= ~(1 << 22);
|
||||
#endif
|
||||
|
||||
/* disable the MMU, caches and etc. */
|
||||
arm_write_cr(cr);
|
||||
|
||||
#if WITH_CACHE && CLEAN_INV_CACHE_ON_QUIESCE
|
||||
/* clean and/or invalidate the caches */
|
||||
arm_clean_invalidate_dcache();
|
||||
arm_invalidate_icache();
|
||||
#endif
|
||||
|
||||
#if CPU_APPLE_SWIFT
|
||||
|
||||
#if !CLEAN_INV_CACHE_ON_QUIESCE
|
||||
/* Invalidate all lines in the L1-D cache */
|
||||
arm_invalidate_dcache();
|
||||
#endif
|
||||
|
||||
/* Clear any pending L2C errors */
|
||||
swift_write_l2cerrsts(0);
|
||||
swift_write_l2cerradr(0);
|
||||
#endif /* CPU_APPLE_SWIFT */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_cpu_init_posttasks(void)
|
||||
{
|
||||
#if WITH_ARM_DCC
|
||||
/* initialize the DCC mechanism */
|
||||
arm_dcc_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u_int32_t arch_get_noncached_address(u_int32_t address)
|
||||
{
|
||||
#if WITH_MMU
|
||||
return arm_get_noncached_address(address);
|
||||
#else
|
||||
return address; /* not really any other choice... */
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PERIPH_PORT_REMAP
|
||||
static void config_periph_port_remap(void *base, size_t len)
|
||||
{
|
||||
uint32_t val = (uint32_t)base;
|
||||
|
||||
switch (len) {
|
||||
case 0: val |= 0x0; break;
|
||||
case 0x1000: val |= 0x3; break;
|
||||
case 0x2000: val |= 0x4; break;
|
||||
case 0x4000: val |= 0x5; break;
|
||||
case 0x8000: val |= 0x6; break;
|
||||
case 0x10000: val |= 0x7; break;
|
||||
case 0x20000: val |= 0x8; break;
|
||||
case 0x40000: val |= 0x9; break;
|
||||
case 0x80000: val |= 0xa; break;
|
||||
case 0x100000: val |= 0xb; break;
|
||||
case 0x200000: val |= 0xc; break;
|
||||
case 0x400000: val |= 0xd; break;
|
||||
case 0x800000: val |= 0xe; break;
|
||||
case 0x1000000: val |= 0xf; break;
|
||||
case 0x2000000: val |= 0x10; break;
|
||||
case 0x4000000: val |= 0x11; break;
|
||||
case 0x8000000: val |= 0x12; break;
|
||||
case 0x10000000: val |= 0x13; break;
|
||||
case 0x20000000: val |= 0x14; break;
|
||||
case 0x40000000: val |= 0x15; break;
|
||||
case 0x80000000: val |= 0x16; break;
|
||||
}
|
||||
|
||||
arm_write_perip_port_remap(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool cpu_setup_mmu(bool resume)
|
||||
{
|
||||
#if WITH_MMU
|
||||
arm_mmu_init(resume);
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#if WITH_MPU
|
||||
arm_mpu_init();
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include <debug.h>
|
||||
#include <sys.h>
|
||||
#include <sys/task.h>
|
||||
#include <lib/cbuf.h>
|
||||
|
||||
#define DSCR_WDTR_FULL (1L<<29)
|
||||
#define DSCR_RDTR_FULL (1L<<30)
|
||||
|
||||
#if ARM_DCC_SYNCHRONOUS
|
||||
static bool dcc_wait_tx = true;
|
||||
#else
|
||||
static bool dcc_wait_tx;
|
||||
#endif
|
||||
|
||||
#ifndef DCC_TX_BUFFER_SIZE
|
||||
# define DCC_TX_BUFFER_SIZE 256
|
||||
#endif
|
||||
|
||||
static struct cbuf *dcc_output_cbuf;
|
||||
|
||||
extern u_int32_t read_dtr(void);
|
||||
extern void write_dtr(u_int32_t c);
|
||||
extern u_int32_t read_dscr(void);
|
||||
|
||||
void arm_write_dcc_char(int c)
|
||||
{
|
||||
if (dcc_wait_tx) {
|
||||
while (read_dscr() & DSCR_WDTR_FULL);
|
||||
write_dtr(c);
|
||||
} else {
|
||||
if (dcc_output_cbuf != 0)
|
||||
cbuf_write_char(dcc_output_cbuf, c);
|
||||
}
|
||||
}
|
||||
|
||||
int arm_read_dcc_char(void)
|
||||
{
|
||||
while (!(read_dscr() & DSCR_RDTR_FULL));
|
||||
|
||||
return read_dtr();
|
||||
}
|
||||
|
||||
int arm_read_dcc_char_nowait(void)
|
||||
{
|
||||
if (!(read_dscr() & DSCR_RDTR_FULL))
|
||||
return -1;
|
||||
|
||||
return read_dtr();
|
||||
}
|
||||
|
||||
static int dcc_read_task(void *arg)
|
||||
{
|
||||
for(;;) {
|
||||
int c;
|
||||
|
||||
c = arm_read_dcc_char_nowait();
|
||||
if (c >= 0) {
|
||||
if (c != '\r')
|
||||
debug_pushchar(c);
|
||||
}
|
||||
task_sleep(1 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dcc_write_task(void *arg)
|
||||
{
|
||||
for(;;) {
|
||||
ssize_t ret;
|
||||
char c;
|
||||
|
||||
ret = cbuf_read_char(dcc_output_cbuf, &c);
|
||||
if (ret == 1) {
|
||||
while(read_dscr() & DSCR_WDTR_FULL)
|
||||
task_yield();
|
||||
write_dtr(c);
|
||||
}
|
||||
task_sleep(1 * 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arm_dcc_init(void)
|
||||
{
|
||||
if (arm_read_dcc_char_nowait() >= 0)
|
||||
dcc_wait_tx = true;
|
||||
|
||||
if (!dcc_wait_tx) {
|
||||
dcc_output_cbuf = cbuf_create(DCC_TX_BUFFER_SIZE, NULL);
|
||||
task_start(task_create("dcc write", &dcc_write_task, NULL, 256));
|
||||
}
|
||||
|
||||
task_start(task_create("dcc read", &dcc_read_task, NULL, 512));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright (C) 2007 Apple Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_ARM_DCC=1
|
||||
|
||||
MODULES += \
|
||||
lib/cbuf
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/dcc.o
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <arch/arm/assembler.h>
|
||||
|
||||
.text
|
||||
|
||||
// u_int32_t arch_get_entropy(volatile u_int32_t *counter_address)
|
||||
//
|
||||
// arch_get_entropy exploits the uncertainty in the asynchronous boundary crossing
|
||||
// between the CPU and a counter. To work correctly, the CPU and counter must be
|
||||
// derived from clocks with relative jitter (PLL vs. OSC). Ideally the inner loop,
|
||||
// up to 32 iterations, should consume a large part of the effective read period of
|
||||
// the counter.
|
||||
//
|
||||
|
||||
ARM_FUNCTION _arch_get_entropy
|
||||
|
||||
mov r1, r0
|
||||
mov r0, #0
|
||||
mov r2, #32
|
||||
1:
|
||||
mov r3, r2
|
||||
2:
|
||||
subs r3, r3, #1
|
||||
bne 2b
|
||||
ldr r3, [r1]
|
||||
and r3, r3, #1
|
||||
orr r0, r3, r0, lsl #1
|
||||
subs r2, r2, #1
|
||||
bne 1b
|
||||
bx lr
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
|
||||
#include <arch/arm/arm.h>
|
||||
#include <arch/arm/assembler.h>
|
||||
|
||||
/*
|
||||
* struct arm_exception_frame {
|
||||
* uint32_t sp;
|
||||
* uint32_t lr;
|
||||
* uint32_t spsr;
|
||||
* uint32_t r[13];
|
||||
* uint32_t pc;
|
||||
* uint64_t fpr[32];
|
||||
* uint32_t fpscr;
|
||||
* uint32_t fpexc;
|
||||
* };
|
||||
*
|
||||
* Note that when returning to the mode in which the exception was
|
||||
* taken that set the I and F bits to mask interrupts and clear the
|
||||
* T bit so that we stay in ARM mode.
|
||||
*/
|
||||
|
||||
#if VFP_REV >= 3
|
||||
|
||||
#define VFP_SAVE \
|
||||
vstmdb.64 sp!, {d0-d3} ; \
|
||||
vstmdb.64 sp!, {d4-d7} ; \
|
||||
vstmdb.64 sp!, {d8-d11} ; \
|
||||
vstmdb.64 sp!, {d12-d15} ; \
|
||||
vstmdb.64 sp!, {d16-d19} ; \
|
||||
vstmdb.64 sp!, {d20-d23} ; \
|
||||
vstmdb.64 sp!, {d24-d27} ; \
|
||||
vstmdb.64 sp!, {d28-d31} ; \
|
||||
fmrx r1, fpscr ; \
|
||||
stmfd sp!, { r1 } ; \
|
||||
fmrx r1, fpexc ; \
|
||||
stmfd sp!, { r1 }
|
||||
|
||||
|
||||
#define VFP_LOAD \
|
||||
ldmfd sp!, { r1 } ; \
|
||||
fmxr fpexc, r1 ; \
|
||||
ldmfd sp!, { r1 } ; \
|
||||
vldmia.64 sp!, {d28-d31} ; \
|
||||
vldmia.64 sp!, {d24-d27} ; \
|
||||
vldmia.64 sp!, {d20-d23} ; \
|
||||
vldmia.64 sp!, {d16-d19} ; \
|
||||
vldmia.64 sp!, {d12-d15} ; \
|
||||
vldmia.64 sp!, {d8-d11} ; \
|
||||
vldmia.64 sp!, {d4-d7} ; \
|
||||
vldmia.64 sp!, {d0-d3} ; \
|
||||
fmxr fpscr, r1
|
||||
|
||||
#else
|
||||
|
||||
#define VFP_SAVE
|
||||
#define VFP_LOAD
|
||||
|
||||
#endif
|
||||
|
||||
#define PUSH_EXCEPTION_FRAME \
|
||||
stmfd sp!, { r0-r12, lr } ; \
|
||||
mrs r0, spsr ; \
|
||||
stmfd sp!, { r0 } ; \
|
||||
orr r0, r0, #0xc0 ; \
|
||||
bic r0, r0, #(1 << 5) ; \
|
||||
mrs r1, cpsr ; \
|
||||
msr cpsr_c, r0 ; \
|
||||
mov r2, sp ; \
|
||||
mov r3, lr ; \
|
||||
msr cpsr_c, r1 ; \
|
||||
stmfd sp!, { r2-r3 }
|
||||
|
||||
#define POP_EXCEPTION_FRAME \
|
||||
add sp, sp, #12 ; \
|
||||
ldmfd sp!, { r0-r12, pc }^
|
||||
|
||||
|
||||
.text
|
||||
/*
|
||||
* Interrupt handling.
|
||||
*
|
||||
* Note that FIQ is not intended to be "fast", but rather an NMI.
|
||||
*/
|
||||
|
||||
ARM_FUNCTION ___arm_irq
|
||||
|
||||
sub lr, lr, #4 /* fix up return address */
|
||||
|
||||
PUSH_EXCEPTION_FRAME
|
||||
VFP_SAVE
|
||||
|
||||
#if ARCH_ARMv7
|
||||
mrs r1, cpsr
|
||||
bic r1, #0x100 /* re-enable imprecise data aborts */
|
||||
msr cpsr_x, r1
|
||||
#endif
|
||||
|
||||
bl _arm_irq /* call handler */
|
||||
|
||||
VFP_LOAD
|
||||
POP_EXCEPTION_FRAME
|
||||
|
||||
|
||||
ARM_FUNCTION ___arm_fiq
|
||||
|
||||
sub lr, lr, #4 /* fix up return address */
|
||||
|
||||
/*
|
||||
* We can't use PUSH_EXCEPTION_FRAME here as we need to save banked registers,
|
||||
* but the only difference should be the re-saving of r8-r12 in the saved mode.
|
||||
*/
|
||||
stmfd sp!, { r0-r12, lr } /* save unbanked registers */
|
||||
mrs r0, spsr /* save spsr */
|
||||
stmfd sp!, { r0 }
|
||||
add r4, sp, #36 /* address of r8 in save frame */
|
||||
orr r0, r0, #0xc0 /* mask interrupts and swap to previous mode */
|
||||
mrs r1, cpsr
|
||||
msr cpsr_c, r0
|
||||
stmia r4, { r8-r12 } /* save banked registers */
|
||||
mov r2, sp /* grab sp & lr, swap back and save them */
|
||||
mov r3, lr
|
||||
msr cpsr_c, r1
|
||||
#if ARCH_ARMv7
|
||||
bic r1, #0x100 /* re-enable imprecise data aborts */
|
||||
msr cpsr_x, r1
|
||||
#endif
|
||||
stmfd sp!, { r2-r3 }
|
||||
|
||||
VFP_SAVE
|
||||
|
||||
bl _arm_fiq /* call handler */
|
||||
|
||||
VFP_LOAD
|
||||
POP_EXCEPTION_FRAME
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Exception handling.
|
||||
*
|
||||
* In each case, the handler is expected to populate the
|
||||
* exception frame structure and call the high-level dispatch
|
||||
* routine. Note that we don't support resuming from any
|
||||
* exceptions other than IRQ/FIQ.
|
||||
*
|
||||
*/
|
||||
|
||||
ARM_FUNCTION ___arm_undefined
|
||||
|
||||
PUSH_EXCEPTION_FRAME
|
||||
|
||||
mov r0, sp
|
||||
bl _arm_undefined
|
||||
b .
|
||||
|
||||
ARM_FUNCTION ___arm_syscall
|
||||
|
||||
PUSH_EXCEPTION_FRAME
|
||||
|
||||
mov r0, sp
|
||||
bl _arm_syscall
|
||||
b .
|
||||
|
||||
ARM_FUNCTION ___arm_prefetch_abort
|
||||
|
||||
sub lr, lr, #4
|
||||
|
||||
PUSH_EXCEPTION_FRAME
|
||||
|
||||
mov r0, sp
|
||||
bl _arm_prefetch_abort
|
||||
b .
|
||||
|
||||
ARM_FUNCTION ___arm_data_abort
|
||||
|
||||
PUSH_EXCEPTION_FRAME
|
||||
|
||||
mov r0, sp
|
||||
bl _arm_data_abort
|
||||
b .
|
||||
|
||||
ARM_FUNCTION ___arm_reserved
|
||||
|
||||
b .
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2015 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include <arch/arm/arm.h>
|
||||
#include <debug.h>
|
||||
#include <sys/task.h>
|
||||
|
||||
/*
|
||||
* VFP/Neon support
|
||||
*/
|
||||
|
||||
#if WITH_VFP
|
||||
|
||||
void
|
||||
arm_fp_init(void)
|
||||
{
|
||||
u_int32_t cr;
|
||||
|
||||
cr = arm_read_cp_access_cr();
|
||||
cr |= CPACR_CP_BITS(10, CPACR_CP_FULL) | CPACR_CP_BITS(11, CPACR_CP_FULL);
|
||||
arm_write_cp_access_cr(cr);
|
||||
}
|
||||
|
||||
#if WITH_VFP_ALWAYS_ON
|
||||
void
|
||||
arm_fp_enable(bool enable)
|
||||
{
|
||||
arm_write_fpexc(FPEXC_EN);
|
||||
|
||||
/* reset VFP/NEON state */
|
||||
arm_write_fpscr(FPSCR_DEFAULT);
|
||||
|
||||
/* zero init VFP/NEON registers */
|
||||
arm_init_fp_regs();
|
||||
}
|
||||
#endif /* WITH_VFP_ALWAYS_ON */
|
||||
|
||||
bool
|
||||
arch_task_fp_enable(bool enable)
|
||||
{
|
||||
bool current;
|
||||
u_int32_t cr;
|
||||
struct task *t;
|
||||
struct arch_task *at;
|
||||
|
||||
/* get the current FP enable state */
|
||||
t = task_get_current_task();
|
||||
at = &t->arch;
|
||||
current = (at->fpexc & FPEXC_EN);
|
||||
|
||||
if (enable != current) {
|
||||
|
||||
/* fetch current hardware state */
|
||||
cr = arm_read_fpexc();
|
||||
if (enable) {
|
||||
/* enable VFP/NEON */
|
||||
at->fpexc = FPEXC_EN;
|
||||
arm_write_fpexc(at->fpexc);
|
||||
|
||||
/* reset VFP/NEON state */
|
||||
at->fpscr = 0;
|
||||
arm_write_fpscr(FPSCR_DEFAULT);
|
||||
|
||||
} else {
|
||||
/* disable VFP/NEON */
|
||||
at->fpexc = cr & ~FPEXC_EN;
|
||||
arm_write_fpexc(at->fpexc);
|
||||
}
|
||||
|
||||
return(!enable);
|
||||
}
|
||||
return(enable);
|
||||
}
|
||||
|
||||
#endif /* WITH_VFP */
|
||||
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2010 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <arch.h>
|
||||
#include <arch/arch_task.h>
|
||||
#include <arch/arm/arm.h>
|
||||
#include <sys.h>
|
||||
#include <lib/libc.h>
|
||||
|
||||
extern void platform_irq(void);
|
||||
extern void platform_fiq(void);
|
||||
|
||||
static const char *arm_abort_decode_status(unsigned int dfsr);
|
||||
static const char *arm_decode_mode(unsigned int status_reg);
|
||||
static void arm_exception_abort(struct arm_exception_frame *frame,
|
||||
const char *kind,
|
||||
unsigned int fsr,
|
||||
unsigned int far) __noreturn;
|
||||
|
||||
static struct arm_exception_frame *arm_get_exception_frame(void) __pure;
|
||||
static struct arm_exception_frame *arm_get_interrupt_frame(void) __pure;
|
||||
static struct arm_exception_frame *arm_get_fiq_frame(void) __pure;
|
||||
static void arm_print_frame_registers(struct arm_exception_frame *frame, const char *prefix);
|
||||
static void arm_backtrace(const char *prefix, u_int32_t pc, u_int32_t fp, u_int32_t stack_base, u_int32_t stack_len);
|
||||
static void arm_stack_for_status_reg(u_int32_t status_reg, u_int32_t *stack_base, u_int32_t *stack_len);
|
||||
|
||||
static bool exception_dump_near_pc;
|
||||
|
||||
#if WITH_MMU
|
||||
static char status_str[32];
|
||||
|
||||
static const char *
|
||||
arm_abort_decode_status(unsigned int fsr)
|
||||
{
|
||||
/* mask bit 10 & low 4 bits for cause decoding */
|
||||
fsr &= FSR_CAUSE_MASK;
|
||||
|
||||
/* ARMv4v5 architecture reference B4-20 */
|
||||
switch (fsr) {
|
||||
case 0x01:
|
||||
case 0x03:
|
||||
return("alignment error");
|
||||
case 0x04:
|
||||
return("icache operation error");
|
||||
case 0x0c:
|
||||
case 0x0e:
|
||||
return("external abort on translation");
|
||||
case 0x05:
|
||||
case 0x07:
|
||||
return("translation error");
|
||||
case 0x09:
|
||||
case 0x0b:
|
||||
return("domain violation");
|
||||
case 0x0d:
|
||||
case 0x0f:
|
||||
return("permission violation");
|
||||
case 0x08:
|
||||
case 0x0a: /* this code is deprecated in ARMv7*/
|
||||
return("precise external abort");
|
||||
case 0x406:
|
||||
return("imprecise external abort"); /* ARMv7 */
|
||||
case 0x40a:
|
||||
return("coprocessor data abort");
|
||||
case 0x408:
|
||||
return("data cache parity error"); /* ARMv7 */
|
||||
case 0x409:
|
||||
return("instruction cache parity error"); /* ARMv7 */
|
||||
case 0x02:
|
||||
return("debug event");
|
||||
}
|
||||
|
||||
snprintf(status_str, sizeof(status_str), "<unknown cause 0x%03x>", fsr);
|
||||
|
||||
return(status_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
arm_decode_mode(unsigned int status_reg)
|
||||
{
|
||||
switch (CPSR_MODE(status_reg)) {
|
||||
case CPSR_MODE_USER:
|
||||
return("user");
|
||||
case CPSR_MODE_FIQ:
|
||||
return("FIQ");
|
||||
case CPSR_MODE_IRQ:
|
||||
return("IRQ");
|
||||
case CPSR_MODE_SUPERVISOR:
|
||||
return("supervisor");
|
||||
case CPSR_MODE_ABORT:
|
||||
return("abort");
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
return("undefined");
|
||||
case CPSR_MODE_SYSTEM:
|
||||
return("system");
|
||||
}
|
||||
return("<unknown>");
|
||||
}
|
||||
|
||||
void
|
||||
arm_data_abort(struct arm_exception_frame *frame)
|
||||
{
|
||||
unsigned int fsr = arm_read_dfsr();
|
||||
unsigned int far = arm_read_dfar();
|
||||
|
||||
frame->pc -= 8;
|
||||
if (fsr == 0x408) {
|
||||
arm_l1cache_dump(1, far);
|
||||
}
|
||||
arm_exception_abort(frame, "data abort", fsr, far);
|
||||
}
|
||||
|
||||
void
|
||||
arm_prefetch_abort(struct arm_exception_frame *frame)
|
||||
{
|
||||
unsigned int fsr = arm_read_ifsr();
|
||||
unsigned int far = arm_read_ifar();
|
||||
|
||||
frame->pc -= 4;
|
||||
if (fsr == 0x409) {
|
||||
arm_l1cache_dump(0, far);
|
||||
}
|
||||
arm_exception_abort(frame, "prefetch abort", fsr, far);
|
||||
}
|
||||
|
||||
void
|
||||
arm_undefined(struct arm_exception_frame *frame)
|
||||
{
|
||||
exception_dump_near_pc = true;
|
||||
frame->pc -= (frame->spsr & CPSR_STATE_THUMB) ? 2: 4;
|
||||
arm_exception_abort(frame, "undefined instruction", ~0, frame->pc);
|
||||
}
|
||||
|
||||
void
|
||||
arm_syscall(struct arm_exception_frame *frame)
|
||||
{
|
||||
exception_dump_near_pc = true;
|
||||
frame->pc -= (frame->spsr & CPSR_STATE_THUMB) ? 2: 4;
|
||||
arm_exception_abort(frame, "syscall", arm_read_ifsr(), frame->pc);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_exception_abort(struct arm_exception_frame *frame, const char *kind, unsigned int fsr, unsigned int far)
|
||||
{
|
||||
#if WITH_MMU
|
||||
panic("ARM %s abort in %s mode at 0x%08x due to %s:\n"
|
||||
" far 0x%08x fsr 0x%08x\n"
|
||||
" r0 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" r4 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" r8 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" sp 0x%08x lr 0x%08x spsr 0x%08x\n",
|
||||
kind, arm_decode_mode(frame->spsr), frame->pc, arm_abort_decode_status(fsr), far, fsr,
|
||||
frame->r[0], frame->r[1], frame->r[2], frame->r[3],
|
||||
frame->r[4], frame->r[5], frame->r[6], frame->r[7],
|
||||
frame->r[8], frame->r[9], frame->r[10], frame->r[11], frame->r[12],
|
||||
frame->sp, frame->lr, frame->spsr);
|
||||
#else
|
||||
panic("ARM %s abort in %s mode at 0x%08x\n"
|
||||
" r0 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" r4 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" r8 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
" sp 0x%08x lr 0x%08x spsr 0x%08x\n",
|
||||
kind, arm_decode_mode(frame->spsr), frame->pc,
|
||||
frame->r[0], frame->r[1], frame->r[2], frame->r[3],
|
||||
frame->r[4], frame->r[5], frame->r[6], frame->r[7],
|
||||
frame->r[8], frame->r[9], frame->r[10], frame->r[11], frame->r[12],
|
||||
frame->sp, frame->lr, frame->spsr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
arm_irq() /* __attribute__ ((naked)) */
|
||||
{
|
||||
#if WITH_FIQ_TIMER
|
||||
// Currently only defined on M7, M7 uses a FIQ for thetimer, and we need to hold off timer interrupts
|
||||
// until we are done running ISR code to prevent unwanted preemption (e.g. <rdar://problem/16757466>)
|
||||
arm_disable_fiqs();
|
||||
#endif
|
||||
_irq_enter_critical_section();
|
||||
platform_irq();
|
||||
_irq_exit_critical_section();
|
||||
#if WITH_FIQ_TIMER
|
||||
arm_enable_fiqs();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
arm_fiq() /* __attribute__ ((naked)) */
|
||||
{
|
||||
_irq_enter_critical_section();
|
||||
platform_fiq();
|
||||
_irq_exit_critical_section();
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessors for exception frame information.
|
||||
*
|
||||
* These may return NULL if we don't believe the frame requested is currently valid.
|
||||
*
|
||||
* Note that not all possible cases of nesting are necessarily handled here; only those
|
||||
* that are likely to be interesting in the case of a fatality.
|
||||
*/
|
||||
static struct arm_exception_frame *
|
||||
arm_get_exception_frame(void)
|
||||
{
|
||||
/*
|
||||
* As exceptions are considered fatal, we don't expect to be asked for
|
||||
* the exception frame in any other context.
|
||||
*/
|
||||
switch (CPSR_MODE(arm_read_cpsr())) {
|
||||
case CPSR_MODE_ABORT:
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
return((struct arm_exception_frame *)exc_stack_top - 1);
|
||||
default:
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct arm_exception_frame *
|
||||
arm_get_interrupt_frame(void)
|
||||
{
|
||||
switch (CPSR_MODE(arm_read_cpsr())) {
|
||||
case CPSR_MODE_ABORT:
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
/*
|
||||
* In some configurations the IRQ and exception stacks share a top,
|
||||
* in which case we can't return the IRQ frame because the exception
|
||||
* frame has overwritten it.
|
||||
*/
|
||||
if (&irq_stack_top == &exc_stack_top)
|
||||
return(NULL);
|
||||
|
||||
/*
|
||||
* If we took an exception while servicing an interrupt, the IRQ frame
|
||||
* will be valid.
|
||||
*/
|
||||
if (CPSR_MODE_IRQ != arm_get_exception_frame()->spsr)
|
||||
return(NULL);
|
||||
break;
|
||||
|
||||
case CPSR_MODE_IRQ:
|
||||
/* we're in interrupt mode, so the frame is valid */
|
||||
break;
|
||||
|
||||
case CPSR_MODE_FIQ:
|
||||
/*
|
||||
* If we took a FIQ while in interrupt mode, the IRQ frame will be
|
||||
* valid.
|
||||
*/
|
||||
if (CPSR_MODE_IRQ != CPSR_MODE(arm_get_fiq_frame()->spsr))
|
||||
return(NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* the interrupt frame is invalid in other modes */
|
||||
return(NULL);
|
||||
}
|
||||
return ((struct arm_exception_frame *)irq_stack_top - 1);
|
||||
}
|
||||
|
||||
static struct arm_exception_frame *
|
||||
arm_get_fiq_frame(void)
|
||||
{
|
||||
switch (CPSR_MODE(arm_read_cpsr())) {
|
||||
case CPSR_MODE_ABORT:
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
/*
|
||||
* If we took an exception while servicing a FIQ, the frame
|
||||
* will be valid.
|
||||
*/
|
||||
if (CPSR_MODE_FIQ != CPSR_MODE(arm_get_exception_frame()->spsr))
|
||||
return(NULL);
|
||||
break;
|
||||
|
||||
case CPSR_MODE_FIQ:
|
||||
/* we're in FIQ mode, so the frame is valid */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* the FIQ frame is invalid in other modes */
|
||||
return(NULL);
|
||||
}
|
||||
return((struct arm_exception_frame *)fiq_stack_top - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* arm_print_frame_registers
|
||||
*
|
||||
* Print the registers from an exception frame.
|
||||
*/
|
||||
static void
|
||||
arm_print_frame_registers(struct arm_exception_frame *frame, const char *prefix)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,
|
||||
"%sr0 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
"%sr4 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
"%sr8 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n"
|
||||
"%spc 0x%08x sp 0x%08x lr 0x%08x spsr 0x%08x\n",
|
||||
prefix, frame->r[0], frame->r[1], frame->r[2], frame->r[3],
|
||||
prefix, frame->r[4], frame->r[5], frame->r[6], frame->r[7],
|
||||
prefix, frame->r[8], frame->r[9], frame->r[10], frame->r[11], frame->r[12],
|
||||
prefix, frame->pc, frame->sp, frame->lr, frame->spsr);
|
||||
}
|
||||
|
||||
/*
|
||||
* arm_backtrace
|
||||
*
|
||||
* Print a backtrace until we run out of frames on the stack.
|
||||
*/
|
||||
static void
|
||||
arm_backtrace(const char *prefix, u_int32_t pc, u_int32_t fp, u_int32_t stack_base, u_int32_t stack_len)
|
||||
{
|
||||
u_int32_t prev_fp;
|
||||
u_int32_t stack_top;
|
||||
u_int32_t *fpp;
|
||||
|
||||
/* print the mode prefix and current pc for starters */
|
||||
dprintf(DEBUG_CRITICAL, " %10s 0x%08x 0x%08x\n", prefix, pc, fp);
|
||||
|
||||
/* sanity check our arguments as much as we can */
|
||||
if ((stack_base % 4) || /* bump these to CPU_CACHELINE_SIZE if/when stack allocation gets smarter */
|
||||
(stack_len % 4) ||
|
||||
(stack_len < 16) ||
|
||||
(stack_len > 100 * 1024)) {
|
||||
dprintf(DEBUG_CRITICAL, "improbable stack, base %p size 0x%08x (task smashed?)\n", (void *)stack_base, stack_len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* loop unwinding frames until we leave the stack region */
|
||||
prev_fp = stack_base;
|
||||
stack_top = stack_base + stack_len;
|
||||
for (;;) {
|
||||
/*
|
||||
* Frame pointer must be aligned, must be above the previous frame, must not point outside the stack.
|
||||
*
|
||||
* It would be nice to have a sentinel to allow differentiating clean termination from a smashed
|
||||
* stack, but that would require support in the interrupt and exception handlers.
|
||||
*/
|
||||
if ((fp % 4) || (fp <= prev_fp) || (fp > stack_top))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Looks like it's inside the stack, so go ahead and deref it.
|
||||
*/
|
||||
fpp = (u_int32_t *)fp;
|
||||
prev_fp = fp;
|
||||
fp = fpp[0];
|
||||
|
||||
/*
|
||||
* Print the return address for this frame.
|
||||
*/
|
||||
dprintf(DEBUG_CRITICAL, " 0x%08x 0x%08x\n", fpp[1], fp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arm_stack_for_status_reg
|
||||
*
|
||||
* Returns the base and size of the stack for the given status register value if it's "special".
|
||||
*/
|
||||
static void
|
||||
arm_stack_for_status_reg(u_int32_t status_reg, u_int32_t *stack_base, u_int32_t *stack_len)
|
||||
{
|
||||
*stack_base = 0;
|
||||
*stack_len = 0;
|
||||
|
||||
#ifdef STACK_BASE
|
||||
*stack_base = (void *)STACK_BASE;
|
||||
switch (CPSR_MODE(status_reg)) {
|
||||
case CPSR_MODE_FIQ:
|
||||
*stack_len = FIQ_STACK_SIZE;
|
||||
break;
|
||||
case CPSR_MODE_IRQ:
|
||||
*stack_len = IRQ_STACK_SIZE;
|
||||
break;
|
||||
case CPSR_MODE_ABORT:
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
*stack_len = EXCEPTION_STACK_SIZE;
|
||||
break;
|
||||
|
||||
}
|
||||
#else
|
||||
switch (CPSR_MODE(status_reg)) {
|
||||
case CPSR_MODE_FIQ:
|
||||
*stack_base = (u_int32_t)fiq_stack_top - FIQ_STACK_SIZE;
|
||||
*stack_len = FIQ_STACK_SIZE;
|
||||
break;
|
||||
case CPSR_MODE_IRQ:
|
||||
*stack_base = (u_int32_t)irq_stack_top - IRQ_STACK_SIZE;
|
||||
*stack_len = IRQ_STACK_SIZE;
|
||||
break;
|
||||
case CPSR_MODE_ABORT:
|
||||
case CPSR_MODE_UNDEFINED:
|
||||
*stack_base = (u_int32_t)exc_stack_top - EXCEPTION_STACK_SIZE;
|
||||
*stack_len = EXCEPTION_STACK_SIZE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* arch_backtrace_current_task
|
||||
*
|
||||
* Print a backtrace for the current task.
|
||||
*
|
||||
* We support being called with the following context nesting:
|
||||
*
|
||||
* supervisor
|
||||
* supervisor interrupt
|
||||
* supervisor FIQ
|
||||
* supervisor exception
|
||||
* supervisor interrupt FIQ
|
||||
* supervisor interrupt exception
|
||||
* supervisor FIQ exception
|
||||
* supervisor interrupt FIQ exception
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
arch_backtrace_current_task(void *stack_base, size_t stack_len)
|
||||
{
|
||||
struct arm_exception_frame *exception_frame, *fiq_frame, *interrupt_frame, *outer_frame;
|
||||
u_int32_t esb, esl;
|
||||
u_int32_t base, count, *insn, offending_pc;
|
||||
|
||||
uintptr_t btext = (uintptr_t)__segment_start(__TEXT);
|
||||
uintptr_t etext = (uintptr_t)__segment_end(__TEXT);
|
||||
|
||||
/*
|
||||
* Find the stack limits for the current context and then backtrace it.
|
||||
*/
|
||||
arm_stack_for_status_reg(arm_read_cpsr(), &esb, &esl);
|
||||
if (0 == esl) {
|
||||
esb = (u_int32_t)stack_base;
|
||||
esl = stack_len;
|
||||
}
|
||||
arm_backtrace(arm_decode_mode(arm_read_cpsr()),
|
||||
(u_int32_t)&arch_backtrace_current_task, (u_int32_t)__builtin_frame_address(0),
|
||||
esb, esl);
|
||||
|
||||
/*
|
||||
* Find valid saved contexts, for the case where we may be in an exception state.
|
||||
*/
|
||||
exception_frame = arm_get_exception_frame();
|
||||
fiq_frame = arm_get_fiq_frame();
|
||||
interrupt_frame = arm_get_interrupt_frame();
|
||||
outer_frame = NULL;
|
||||
|
||||
/*
|
||||
* If we have a valid exception context, backtrace the context it was called from first.
|
||||
* That context may be supervisor, FIQ or interrupt mode. If it was FIQ mode, we will
|
||||
* dump the context the FIQ was called from next.
|
||||
*/
|
||||
if (NULL != exception_frame) {
|
||||
|
||||
/* dump registers at entry to exception mode */
|
||||
arm_print_frame_registers(exception_frame, " ");
|
||||
|
||||
/*
|
||||
* If the exception handler thought that the data around the PC was worth
|
||||
* displaying, and we think the PC was inside the text section, display it here.
|
||||
*/
|
||||
if (true == exception_dump_near_pc) {
|
||||
offending_pc = exception_frame->pc;
|
||||
if ((offending_pc >= btext) && (offending_pc <= etext)) {
|
||||
if ((offending_pc - btext) < 8) {
|
||||
base = btext;
|
||||
} else {
|
||||
base = offending_pc - 8;
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL, " [0x%08x:", base);
|
||||
for (count = 0; count < 4; count++) {
|
||||
insn = (u_int32_t *)base + count;
|
||||
dprintf(DEBUG_CRITICAL, " 0x%08x", *insn);
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL, "]\n");
|
||||
} else {
|
||||
dprintf(DEBUG_CRITICAL, " [pc 0x%08x not in text %p-%p]\n",
|
||||
offending_pc, (void *)btext, (void *)etext);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the exception occurred in a context with a special stack (FIQ or interrupt)
|
||||
* backtrace that stack here.
|
||||
*/
|
||||
arm_stack_for_status_reg(exception_frame->spsr, &esb, &esl);
|
||||
if (0 != esl) {
|
||||
arm_backtrace(arm_decode_mode(exception_frame->spsr),
|
||||
exception_frame->pc, exception_frame->r[7],
|
||||
esb, esl);
|
||||
} else {
|
||||
/* the outer context is in the exception frame */
|
||||
outer_frame = exception_frame;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a valid FIQ context, backtrace the context it was invoked from now.
|
||||
*/
|
||||
if (NULL != fiq_frame) {
|
||||
|
||||
/* dump registers at entry to FIQ mode */
|
||||
arm_print_frame_registers(fiq_frame, " ");
|
||||
|
||||
/*
|
||||
* If the FIQ occurred from interrupt mode, backtrace the interrupt mode stack here.
|
||||
*/
|
||||
arm_stack_for_status_reg(fiq_frame->spsr, &esb, &esl);
|
||||
if (0 != esl) {
|
||||
arm_backtrace(arm_decode_mode(fiq_frame->spsr),
|
||||
fiq_frame->pc, fiq_frame->r[7],
|
||||
esb, esl);
|
||||
} else {
|
||||
/* the outer context is in the FIQ frame */
|
||||
outer_frame = fiq_frame;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have an interrupt-saved context, fetch the task state from it.
|
||||
*/
|
||||
if (NULL != interrupt_frame) {
|
||||
|
||||
/* dump registers at entry to interrupt mode */
|
||||
arm_print_frame_registers(interrupt_frame, " ");
|
||||
|
||||
outer_frame = interrupt_frame;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the task context backtrace from the outer frame.
|
||||
*/
|
||||
if (NULL != outer_frame) {
|
||||
arm_backtrace(arm_decode_mode(outer_frame->spsr),
|
||||
outer_frame->pc, outer_frame->r[7],
|
||||
(u_int32_t)stack_base, (u_int32_t)stack_len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arch_backtrace_task
|
||||
*
|
||||
* Print a backtrace from a saved task context.
|
||||
*/
|
||||
void
|
||||
arch_backtrace_task(struct arch_task *arch_task, void *stack_base, size_t stack_len)
|
||||
{
|
||||
arm_backtrace("supervisor", arch_task->regs[ARM_ARCH_TASK_LR], arch_task->regs[ARM_ARCH_TASK_FP],
|
||||
(u_int32_t)stack_base, (u_int32_t)stack_len);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#ifndef __ARCH_TASK_H
|
||||
#define __ARCH_TASK_H
|
||||
|
||||
/*
|
||||
* Note that this structure is known implicitly by code in context.S, and
|
||||
* must be kept in sync.
|
||||
*/
|
||||
#if defined(__arm__)
|
||||
#ifndef __ASSEMBLY__
|
||||
struct arch_task {
|
||||
/*
|
||||
* Core registers.
|
||||
*/
|
||||
uint32_t regs[10]; // r4-r11, r13, r14
|
||||
|
||||
#if WITH_VFP
|
||||
/*
|
||||
* VFP/Neon registers.
|
||||
*
|
||||
* Note that layout must be kept in sync with offset defines below.
|
||||
*/
|
||||
uint32_t fpexc;
|
||||
uint32_t fpscr;
|
||||
uint64_t fpregs[32];
|
||||
#endif
|
||||
};
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
* Indices for useful core registers.
|
||||
*/
|
||||
#define ARM_ARCH_TASK_FP 3
|
||||
#define ARM_ARCH_TASK_SP 8
|
||||
#define ARM_ARCH_TASK_LR 9
|
||||
|
||||
/*
|
||||
* VFP/Neon field offsets - it would be nice to generate these automatically.
|
||||
*/
|
||||
#define ARM_ARCH_TASK_FP_OFFSET 40
|
||||
#define ARM_ARCH_TASK_FPEXC (ARM_ARCH_TASK_FP_OFFSET + 0)
|
||||
#define ARM_ARCH_TASK_FPSCR (ARM_ARCH_TASK_FP_OFFSET + 4)
|
||||
#define ARM_ARCH_TASK_FPREGS (ARM_ARCH_TASK_FP_OFFSET + 8)
|
||||
|
||||
|
||||
#elif defined(__arm64__)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
typedef __uint128_t uint128_t;
|
||||
|
||||
struct arch_task {
|
||||
/* Core registers */
|
||||
uint64_t regs[29]; // x0-x28
|
||||
uint64_t fp;
|
||||
uint64_t lr;
|
||||
uint64_t sp;
|
||||
#if WITH_VFP
|
||||
/* Neon registers */
|
||||
union {
|
||||
uint128_t q;
|
||||
uint64_t d;
|
||||
uint32_t s;
|
||||
} vregs[32]; // v0-v31
|
||||
uint32_t fpsr;
|
||||
uint32_t fpcr;
|
||||
#endif
|
||||
};
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __arm64__ */
|
||||
|
||||
#endif /* ! __ARCH_TASK_H */
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#ifndef __ARM_H
|
||||
#define __ARM_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <compiler.h>
|
||||
#include <non_posix_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
unsigned int arm_read_cpsr(void) __pure;
|
||||
|
||||
unsigned int arm_read_main_id(void) __pure;
|
||||
unsigned int arm_read_cache_id(void) __pure;
|
||||
unsigned int arm_read_cache_level_id(void) __pure;
|
||||
unsigned int arm_read_cache_size_selection(void) __pure;
|
||||
void arm_write_cache_size_selection(unsigned int);
|
||||
unsigned int arm_read_cache_size_id(void) __pure;
|
||||
|
||||
void arm_read_memory_model_feature_regs(unsigned int regs[4]) __pure;
|
||||
void arm_read_instruction_set_attribute_regs(unsigned int regs[6]) __pure;
|
||||
void arm_read_extended_feature_regs(unsigned int regs[16]) __pure;
|
||||
|
||||
unsigned int arm_read_cr(void) __pure;
|
||||
void arm_write_cr(unsigned int cr);
|
||||
unsigned int arm_read_aux_cr(void) __pure;
|
||||
void arm_write_aux_cr(unsigned int cr);
|
||||
unsigned int arm_read_perip_port_remap(void) __pure;
|
||||
void arm_write_perip_port_remap(unsigned int val);
|
||||
|
||||
extern uint32_t arm_read_cp_access_cr(void) __pure;
|
||||
extern void arm_write_cp_access_cr(uint32_t val);
|
||||
|
||||
extern void arm_fp_init(void);
|
||||
extern void arm_fp_enable(bool);
|
||||
|
||||
extern uint32_t arm_read_fpexc(void) __pure;
|
||||
extern void arm_write_fpexc(uint32_t val);
|
||||
|
||||
extern uint32_t arm_read_fpscr(void) __pure;
|
||||
extern void arm_write_fpscr(uint32_t val);
|
||||
|
||||
extern void arm_init_fp_regs();
|
||||
|
||||
#if ARCH_ARMv7
|
||||
extern uint32_t arm_read_l2_aux_cr(void) __pure;
|
||||
extern void arm_write_l2_aux_cr(uint32_t val);
|
||||
|
||||
typedef enum {
|
||||
ARM_PMCR = 0, /* The order here matches a jump table in asm.S */
|
||||
ARM_PMCNTENSET,
|
||||
ARM_PMCNTENCLR,
|
||||
ARM_PMOVSR,
|
||||
ARM_PMSWINC,
|
||||
ARM_PMSELR,
|
||||
|
||||
ARM_PMCCNTR,
|
||||
ARM_PMXEVTYPER,
|
||||
ARM_PMXEVCNTR,
|
||||
|
||||
ARM_PMUSERNR,
|
||||
ARM_PMINTENSET,
|
||||
ARM_PMINTENCLR,
|
||||
} arm_pmreg_t;
|
||||
|
||||
extern uint32_t arm_read_pmreg(arm_pmreg_t reg) __pure;
|
||||
extern void arm_write_pmreg(arm_pmreg_t reg, uint32_t val);
|
||||
#endif /* ARCH_ARMv7 */
|
||||
|
||||
#if ARCH_ARMv8
|
||||
|
||||
extern void arm_write_mair(uint64_t mair);
|
||||
extern void arm_write_tcr(uint64_t tcr);
|
||||
extern void arm_write_ttbr0(void *ttbr0);
|
||||
extern void arm_store_pte(uint64_t *ent_p, uint64_t ent);
|
||||
|
||||
#if WITH_L2_AS_RAM
|
||||
extern uint64_t arm_read_l2_cramconfig(void);
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_ARMv8 */
|
||||
|
||||
void arm_mmu_init(bool resume);
|
||||
void arm_mpu_init(void);
|
||||
|
||||
uint32_t arm_get_noncached_address(uint32_t address);
|
||||
|
||||
void arm_write_dar(unsigned int dar);
|
||||
void arm_write_ttb(void *tt);
|
||||
void arm_write_ttbcr(unsigned int ttbc);
|
||||
|
||||
#if WITH_MMU
|
||||
#define FSR_CAUSE_MASK ((1 << 10) | (0xF << 0))
|
||||
unsigned int arm_read_ifsr(void) __pure;
|
||||
unsigned int arm_read_dfsr(void) __pure;
|
||||
unsigned int arm_read_dfar(void) __pure;
|
||||
unsigned int arm_read_ifar(void) __pure;
|
||||
#else
|
||||
# define arm_read_ifsr() ~0
|
||||
# define arm_read_dfsr() ~0
|
||||
# define arm_read_dfar() ~0
|
||||
# define arm_read_ifar() ~0
|
||||
#endif
|
||||
|
||||
#if WITH_CACHE_DEBUG
|
||||
void arm_l1cache_dump(int dcache, unsigned int addr);
|
||||
#else
|
||||
#define arm_l1cache_dump(dcache, addr)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exception frame saved at the top of the exception/interrupt stacks.
|
||||
*/
|
||||
struct arm_exception_frame {
|
||||
uint32_t sp; /* saved stack pointer (r13) */
|
||||
uint32_t lr; /* saved link register (r14) */
|
||||
uint32_t spsr; /* saved cpsr */
|
||||
uint32_t r[13]; /* r0 - r12 */
|
||||
uint32_t pc; /* saved pc (r15) */
|
||||
};
|
||||
|
||||
struct arm_exception_frame64 {
|
||||
uint64_t regs[29]; // x0-x28
|
||||
uint64_t fp;
|
||||
uint64_t lr;
|
||||
uint64_t sp;
|
||||
uint32_t spsr;
|
||||
uint32_t reserved0;
|
||||
uint64_t pc;
|
||||
uint64_t far;
|
||||
uint32_t esr;
|
||||
uint32_t reserved1;
|
||||
};
|
||||
|
||||
extern void *irq_stack_top; /* stacks defined in start.S */
|
||||
extern void *fiq_stack_top;
|
||||
extern void *exc_stack_top;
|
||||
extern void *svc_stack_top;
|
||||
|
||||
void arm_flush_tlbs(void);
|
||||
|
||||
void arm_invalidate_dcache(void);
|
||||
void arm_invalidate_icache(void);
|
||||
void arm_clean_caches(void);
|
||||
void arm_clean_dcache(void);
|
||||
void arm_clean_dcache_line(addr_t addr);
|
||||
void arm_clean_dcache_line_2(addr_t addr);
|
||||
void arm_clean_dcache_line_3(addr_t addr);
|
||||
void arm_clean_dcache_line_4(addr_t addr);
|
||||
void arm_clean_dcache_line_5(addr_t addr);
|
||||
void arm_clean_dcache_line_6(addr_t addr);
|
||||
void arm_clean_dcache_line_7(addr_t addr);
|
||||
void arm_clean_dcache_line_8(addr_t addr);
|
||||
void arm_invalidate_dcache_line(addr_t addr);
|
||||
void arm_invalidate_dcache_line_2(addr_t addr);
|
||||
void arm_invalidate_dcache_line_3(addr_t addr);
|
||||
void arm_invalidate_dcache_line_4(addr_t addr);
|
||||
void arm_invalidate_dcache_line_5(addr_t addr);
|
||||
void arm_invalidate_dcache_line_6(addr_t addr);
|
||||
void arm_invalidate_dcache_line_7(addr_t addr);
|
||||
void arm_invalidate_dcache_line_8(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_2(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_3(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_4(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_5(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_6(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_7(addr_t addr);
|
||||
void arm_clean_invalidate_dcache_line_8(addr_t addr);
|
||||
void arm_clean_invalidate_dcache(void);
|
||||
|
||||
void arm_enable_l1parity(void);
|
||||
|
||||
void arm_drain_write_buffer(void);
|
||||
|
||||
void arm_flush_branch_predictor(void);
|
||||
|
||||
void arm_init_vfp(void);
|
||||
void arm_enable_vfp(void);
|
||||
void arm_disable_vfp(void);
|
||||
|
||||
void arm_enable_fiqs(void);
|
||||
void arm_disable_fiqs(void);
|
||||
|
||||
unsigned int arm_read_vbar(void);
|
||||
void arm_write_vbar(unsigned int addr);
|
||||
|
||||
void arm_memory_barrier(void);
|
||||
|
||||
/* mmu stuff */
|
||||
#ifdef ARCH_ARMv8
|
||||
|
||||
typedef enum {
|
||||
kARMMMUDeviceRX,
|
||||
kARMMMUDeviceR,
|
||||
kARMMMUDeviceRW,
|
||||
kARMMMUNormalRX,
|
||||
kARMMMUNormalR,
|
||||
kARMMMUNormalRW,
|
||||
kARMMMUNumExtendedAttr,
|
||||
} arm_mmu_extended_attr_t;
|
||||
|
||||
void arm_mmu_map_range(addr_t vaddr, addr_t paddr, size_t size, arm_mmu_extended_attr_t attr);
|
||||
|
||||
// map in place using the specified attributes
|
||||
void arm_mmu_map_rw(addr_t addr, size_t size);
|
||||
void arm_mmu_map_rx(addr_t addr, size_t size);
|
||||
void arm_mmu_map_ro(addr_t addr, size_t size);
|
||||
void arm_mmu_map_device_rw(addr_t addr, size_t size);
|
||||
void arm_mmu_map_device_rx(addr_t addr, size_t size);
|
||||
void arm_mmu_map_device_ro(addr_t addr, size_t size);
|
||||
|
||||
#else
|
||||
|
||||
typedef enum {
|
||||
kARMMMUStronglyOrdered = 0,
|
||||
kARMMMUDevice,
|
||||
kARMMMUNormal,
|
||||
kARMMMUInnerNormalOuterNoncached,
|
||||
kARMMMUWriteCombined,
|
||||
kARMMMUNormalRX,
|
||||
kARMMMUNumAttr,
|
||||
} arm_mmu_attr_t;
|
||||
|
||||
// Section and page mapping is explicit as there is always a fixed
|
||||
// granule at each level (without LPAE) in ARMv4-ARMv7.
|
||||
void arm_mmu_map_section(addr_t vaddr, addr_t paddr, arm_mmu_attr_t attr, bool shared);
|
||||
void arm_mmu_map_section_range(addr_t vaddr, addr_t paddr, size_t sections, arm_mmu_attr_t attr, bool shared, bool flush);
|
||||
|
||||
#endif
|
||||
|
||||
/* mpu stuff */
|
||||
void mpu_init(void);
|
||||
void arm_write_dprot_region_0(uint32_t base_size);
|
||||
void arm_write_dprot_region_1(uint32_t base_size);
|
||||
void arm_write_dprot_region_2(uint32_t base_size);
|
||||
void arm_write_dprot_region_3(uint32_t base_size);
|
||||
void arm_write_dprot_region_4(uint32_t base_size);
|
||||
void arm_write_dprot_region_5(uint32_t base_size);
|
||||
void arm_write_dprot_region_6(uint32_t base_size);
|
||||
void arm_write_dprot_region_7(uint32_t base_size);
|
||||
void arm_write_iprot_region_0(uint32_t base_size);
|
||||
void arm_write_iprot_region_1(uint32_t base_size);
|
||||
void arm_write_iprot_region_2(uint32_t base_size);
|
||||
void arm_write_iprot_region_3(uint32_t base_size);
|
||||
void arm_write_iprot_region_4(uint32_t base_size);
|
||||
void arm_write_iprot_region_5(uint32_t base_size);
|
||||
void arm_write_iprot_region_6(uint32_t base_size);
|
||||
void arm_write_iprot_region_7(uint32_t base_size);
|
||||
void arm_write_data_prot_register(uint32_t prot);
|
||||
void arm_write_ins_prot_register(uint32_t prot);
|
||||
void arm_write_cacheable_registers(uint32_t dcache, uint32_t icache);
|
||||
void arm_write_bufferable_register(uint32_t buff);
|
||||
|
||||
/* thread id */
|
||||
uint32_t arm_read_user_ro_tid(void) __pure;
|
||||
uint32_t arm_read_user_rw_tid(void) __pure;
|
||||
uint32_t arm_read_sup_tid(void) __pure;
|
||||
void arm_write_user_ro_tid(uint32_t tid);
|
||||
void arm_write_user_rw_tid(uint32_t tid);
|
||||
void arm_write_sup_tid(uint32_t tid);
|
||||
|
||||
/* DCC based debug */
|
||||
void arm_write_dcc_char(int c);
|
||||
int arm_read_dcc_char(void);
|
||||
int arm_read_dcc_char_nowait(void);
|
||||
int arm_dcc_init(void);
|
||||
|
||||
#if CPU_APPLE_SWIFT
|
||||
extern uint32_t swift_read_l2cerrsts(void) __pure;
|
||||
extern void swift_write_l2cerrsts(uint32_t l2cerrsts);
|
||||
extern uint32_t swift_read_l2cerradr(void) __pure;
|
||||
extern void swift_write_l2cerradr(uint32_t l2cerradr);
|
||||
#endif /* CPU_APPLE_SWIFT */
|
||||
|
||||
/* FP support */
|
||||
#if WITH_VFP
|
||||
void arm_call_fpsaved(void *arg, void (*func)(void *arg));
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#define CPSR_MODE(_x) ((_x) & 0x1f)
|
||||
#define CPSR_MODE_USER 0x10
|
||||
#define CPSR_MODE_FIQ 0x11
|
||||
#define CPSR_MODE_IRQ 0x12
|
||||
#define CPSR_MODE_SUPERVISOR 0x13
|
||||
#define CPSR_MODE_ABORT 0x17
|
||||
#define CPSR_MODE_UNDEFINED 0x1b
|
||||
#define CPSR_MODE_SYSTEM 0x1f
|
||||
|
||||
#define CPSR_STATE_THUMB 0x20
|
||||
|
||||
#define CPACR_CP_BITS(_cp, _bits) ((_bits) << ((_cp) * 2))
|
||||
#define CPACR_CP_DENIED 0x0
|
||||
#define CPACR_CP_PRIVILEGED 0x1
|
||||
#define CPACR_CP_FULL 0x3
|
||||
|
||||
#define FPEXC_EX (1<<31)
|
||||
#define FPEXC_EN (1<<30)
|
||||
#define FPEXC_FP2V (1<<28)
|
||||
|
||||
#define FPSCR_DEFAULT (1<<25) | (1<<24) // DN, FZ bits
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Declare a globally-visible ARM function
|
||||
*/
|
||||
.macro ARM_FUNCTION
|
||||
.text
|
||||
.arm
|
||||
.balign 4
|
||||
.global $0
|
||||
$0:
|
||||
.endmacro
|
||||
|
||||
/*
|
||||
* Declare a globally-visible THUMB function
|
||||
*/
|
||||
.macro THUMB_FUNCTION
|
||||
.text
|
||||
.thumb_func $0
|
||||
.balign 2
|
||||
.global $0
|
||||
$0:
|
||||
.endmacro
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
_start
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2011 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <compiler.h>
|
||||
#include <sys.h>
|
||||
#include <arch.h>
|
||||
#include <arch/arm/arm.h>
|
||||
#include <platform.h>
|
||||
#include <platform/memmap.h>
|
||||
|
||||
#define SECTION_SIZE MB
|
||||
#define LARGE_PAGE_SIZE 65536
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
#define TTBCR_PD1 (1 << 5)
|
||||
|
||||
typedef u_int32_t tt_ent;
|
||||
|
||||
/* needs to be in non-static, initialized data for successful patching
|
||||
* during IOP firmware loading */
|
||||
u_int32_t tt_size __attribute__((used)) = MMU_TT_SIZE;
|
||||
tt_ent *tt = (void *)0xffffffff;
|
||||
|
||||
/* ARM MMU first-level section descriptor definitions */
|
||||
#define ARM_DESC_SECT ((0 << 18) | (1 << 1))
|
||||
#define ARM_SECT_B (1 << 2)
|
||||
#define ARM_SECT_C (1 << 3)
|
||||
#define ARM_SECT_XN (1 << 4)
|
||||
#define ARM_SECT_DOMAIN(_d) ((_d) << 5)
|
||||
#define ARM_SECT_TEX(_t) ((_t) << 12)
|
||||
#define ARM_SECT_SHARED (1 << 16)
|
||||
#define ARM_SECT_FULLACC ((0 << 15) | (3 << 10))
|
||||
#define ARM_SECT_EXEC (ARM_SECT_DOMAIN(0))
|
||||
#define ARM_SECT_NOEXEC (ARM_SECT_DOMAIN(1) | ARM_SECT_XN)
|
||||
#define ARM_SECT_READ_ONLY (1 << 15)
|
||||
|
||||
/* Non-normal memory needs XN set (and consequently a client domain assignment) to avoid
|
||||
* instruction prefetch to those regions */
|
||||
static u_int32_t sect_flags[] = {
|
||||
[kARMMMUStronglyOrdered] = ARM_SECT_NOEXEC | ARM_SECT_FULLACC,
|
||||
[kARMMMUDevice] = ARM_SECT_NOEXEC | ARM_SECT_B | ARM_SECT_FULLACC,
|
||||
[kARMMMUNormal] = ARM_SECT_EXEC | ARM_SECT_C | ARM_SECT_B | ARM_SECT_FULLACC,
|
||||
[kARMMMUInnerNormalOuterNoncached] = ARM_SECT_EXEC | ARM_SECT_TEX(4) | ARM_SECT_C | ARM_SECT_B | ARM_SECT_FULLACC,
|
||||
[kARMMMUWriteCombined] = ARM_SECT_NOEXEC | ARM_SECT_TEX(1) | ARM_SECT_FULLACC,
|
||||
[kARMMMUNormalRX] = ARM_SECT_DOMAIN(1) | ARM_SECT_C | ARM_SECT_B | ARM_SECT_READ_ONLY | ARM_SECT_FULLACC,
|
||||
};
|
||||
|
||||
static tt_ent attr_to_sect_flags(arm_mmu_attr_t attr)
|
||||
{
|
||||
if (attr >= kARMMMUNumAttr)
|
||||
attr = kARMMMUStronglyOrdered;
|
||||
return sect_flags[attr];
|
||||
}
|
||||
|
||||
void arm_mmu_map_section(addr_t vaddr, addr_t paddr, arm_mmu_attr_t attr, bool shared)
|
||||
{
|
||||
if ((vaddr & (SECTION_SIZE - 1)) != 0)
|
||||
panic("section virtual address base is nonzero");
|
||||
if ((paddr & (SECTION_SIZE - 1)) != 0)
|
||||
panic("section physical address base is nonzero");
|
||||
|
||||
tt[vaddr / MB] = paddr | ARM_DESC_SECT | attr_to_sect_flags(attr) | (shared ? ARM_SECT_SHARED : 0);
|
||||
|
||||
arm_clean_dcache_line((unsigned long)&tt[vaddr / MB]);
|
||||
arm_flush_tlbs();
|
||||
}
|
||||
|
||||
void arm_mmu_map_section_range(addr_t vaddr, addr_t paddr, size_t sections, arm_mmu_attr_t attr, bool shared, bool flush)
|
||||
{
|
||||
tt_ent entry, *tt_ptr;
|
||||
addr_t flush_start, flush_stop;
|
||||
u_int32_t cnt;
|
||||
|
||||
if ((vaddr & (SECTION_SIZE - 1)) != 0)
|
||||
panic("section range virtual address base is nonzero");
|
||||
if ((paddr & (SECTION_SIZE - 1)) != 0)
|
||||
panic("section range physical address base is nonzero");
|
||||
|
||||
entry = paddr | ARM_DESC_SECT | attr_to_sect_flags(attr) | (shared ? ARM_SECT_SHARED : 0);
|
||||
tt_ptr = &tt[vaddr / MB];
|
||||
|
||||
while (sections > 0) {
|
||||
cnt = (sections < 16) ? sections : 16;
|
||||
switch (cnt) {
|
||||
case 16 : tt_ptr[15] = entry + MB * 15;
|
||||
case 15 : tt_ptr[14] = entry + MB * 14;
|
||||
case 14 : tt_ptr[13] = entry + MB * 13;
|
||||
case 13 : tt_ptr[12] = entry + MB * 12;
|
||||
case 12 : tt_ptr[11] = entry + MB * 11;
|
||||
case 11 : tt_ptr[10] = entry + MB * 10;
|
||||
case 10 : tt_ptr[ 9] = entry + MB * 9;
|
||||
case 9 : tt_ptr[ 8] = entry + MB * 8;
|
||||
case 8 : tt_ptr[ 7] = entry + MB * 7;
|
||||
case 7 : tt_ptr[ 6] = entry + MB * 6;
|
||||
case 6 : tt_ptr[ 5] = entry + MB * 5;
|
||||
case 5 : tt_ptr[ 4] = entry + MB * 4;
|
||||
case 4 : tt_ptr[ 3] = entry + MB * 3;
|
||||
case 3 : tt_ptr[ 2] = entry + MB * 2;
|
||||
case 2 : tt_ptr[ 1] = entry + MB * 1;
|
||||
case 1 : tt_ptr[ 0] = entry + MB * 0;
|
||||
}
|
||||
|
||||
entry += MB * cnt;
|
||||
tt_ptr += cnt;
|
||||
sections -= cnt;
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
flush_start = ((addr_t)&tt[vaddr / MB]) & ~CPU_CACHELINE_SIZE;
|
||||
flush_stop = ((addr_t)tt_ptr + (CPU_CACHELINE_SIZE - 1)) & ~CPU_CACHELINE_SIZE;
|
||||
|
||||
while (flush_start < flush_stop) {
|
||||
arm_clean_dcache_line(flush_start);
|
||||
|
||||
flush_start += CPU_CACHELINE_SIZE;
|
||||
}
|
||||
|
||||
arm_flush_tlbs();
|
||||
}
|
||||
}
|
||||
|
||||
void arm_mmu_init(bool resume)
|
||||
{
|
||||
#ifdef MMU_TT_BASE
|
||||
/* TT usually at the end of memory */
|
||||
tt = (tt_ent *)MMU_TT_BASE;
|
||||
#endif
|
||||
|
||||
if (false == resume) {
|
||||
/* identity map everything using the translation table as noncached */
|
||||
arm_mmu_map_section_range(0, 0, MMU_TT_SIZE / sizeof(tt_ent), kARMMMUStronglyOrdered, false, false);
|
||||
}
|
||||
|
||||
/* let the platform code get a shot at mapping some ranges */
|
||||
platform_mmu_setup(resume);
|
||||
|
||||
/* set up the domain register */
|
||||
arm_write_dar(0x7); /* domain 0 manager, domain 1 client */
|
||||
|
||||
/* write the new translation table */
|
||||
#if MMU_TT_SIZE == 0x4000
|
||||
arm_write_ttbcr(0);
|
||||
#elif (MMU_TT_SIZE == 0x1000) && (WITH_MMU_SECURITY_EXTENSIONS)
|
||||
arm_write_ttbcr(2 | TTBCR_PD1);
|
||||
#else
|
||||
#error "Must set up TTBCR appropriately for translation table smaller than 16 kB"
|
||||
#endif
|
||||
arm_write_ttb(tt);
|
||||
|
||||
arm_flush_tlbs();
|
||||
}
|
||||
|
||||
u_int32_t arm_get_noncached_address(u_int32_t address)
|
||||
{
|
||||
#ifdef MMU_NONCACHE0_SIZE
|
||||
if (((int32_t)(address - MMU_NONCACHE0_PBASE) >= 0) && ((address - MMU_NONCACHE0_PBASE) < MMU_NONCACHE0_SIZE)) {
|
||||
return address - MMU_NONCACHE0_PBASE + MMU_NONCACHE0_VBASE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MMU_NONCACHE1_SIZE
|
||||
if (((int32_t)(address - MMU_NONCACHE1_PBASE) >= 0) && ((address - MMU_NONCACHE1_PBASE) < MMU_NONCACHE1_SIZE)) {
|
||||
return address - MMU_NONCACHE1_PBASE + MMU_NONCACHE1_VBASE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include <platform/memmap.h>
|
||||
#include <sys.h>
|
||||
|
||||
void arm_mpu_init(void)
|
||||
{
|
||||
/* set everything as fully cached, except for the hardware register region */
|
||||
arm_write_iprot_region_0(0x0000003f);
|
||||
arm_write_dprot_region_0(0x0000003f);
|
||||
#ifdef PERIPH_BASE
|
||||
arm_write_dprot_region_1((PERIPH_BASE | (0x1F - ((PERIPH_LEN == 0) ? 0 : (__builtin_clz(PERIPH_LEN) + 1))) << 1) | 1);
|
||||
#endif
|
||||
arm_write_ins_prot_register(0x3); // region 0 full access
|
||||
arm_write_data_prot_register(0xf); // region 0 & 1 full access
|
||||
arm_write_cacheable_registers(0x1, 0x1); // region 0 data and instruction is cacheable
|
||||
arm_write_bufferable_register(0x1); // data region 0 is write bufferable
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
# Copyright (C) 2007-2010 Apple Inc. All rights reserved.
|
||||
# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Computer, Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Computer, Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
#
|
||||
# ARM CPU config
|
||||
#
|
||||
|
||||
# sanity check
|
||||
ifeq ($(ARM_CPU),)
|
||||
$(error ARM_CPU is not set)
|
||||
endif
|
||||
|
||||
ifneq ($(ARM_ARCH),)
|
||||
$(info ARM_ARCH does not need to be set at the platform level)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Per-CPU configuration
|
||||
################################################################################
|
||||
|
||||
#
|
||||
# Apple Swift
|
||||
#
|
||||
ifeq ($(ARM_CPU),apple-swift)
|
||||
ARM_ARCH ?= armv7
|
||||
ARM_ARCH_OPTIONS := ARCH_ARMv7=1 WITH_VFP=1
|
||||
OPTIONS += \
|
||||
CPU_APPLE_SWIFT=1 \
|
||||
WITH_MMU=1 \
|
||||
WITH_MMU_SECURITY_EXTENSIONS=1 \
|
||||
WITH_CACHE=1 \
|
||||
CPU_CACHELINE_SIZE=64 \
|
||||
CPU_CACHELINE_SHIFT=6 \
|
||||
CPU_CACHEINDEX_SHIFT=8 \
|
||||
CPU_CACHESET_SHIFT=3 \
|
||||
WITH_BRANCH_PREDICTION=1 \
|
||||
WITH_UNALIGNED_MEM=1 \
|
||||
WITH_L1_PARITY=1 \
|
||||
PAGE_SIZE=4096
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cache_v7.o \
|
||||
$(LOCAL_DIR)/mmu.o \
|
||||
$(LOCAL_DIR)/fp.o
|
||||
endif
|
||||
|
||||
#
|
||||
# ARM Cortex A8
|
||||
#
|
||||
ifeq ($(ARM_CPU),cortex-a8)
|
||||
ARM_ARCH ?= armv7
|
||||
ARM_ARCH_OPTIONS := ARCH_ARMv7=1 WITH_VFP=1
|
||||
OPTIONS += \
|
||||
CPU_ARM_CORTEX_A8=1 \
|
||||
WITH_MMU=1 \
|
||||
WITH_MMU_SECURITY_EXTENSIONS=1 \
|
||||
WITH_CACHE=1 \
|
||||
CPU_CACHELINE_SIZE=64 \
|
||||
CPU_CACHELINE_SHIFT=6 \
|
||||
CPU_CACHEINDEX_SHIFT=7 \
|
||||
CPU_CACHESET_SHIFT=2 \
|
||||
WITH_BRANCH_PREDICTION=1 \
|
||||
WITH_UNALIGNED_MEM=1 \
|
||||
WITH_L1_PARITY=1 \
|
||||
WITH_CACHE_DEBUG=1 \
|
||||
WITH_ARCHITECTED_L2=1 \
|
||||
WITH_AUX_L2_ENABLE_BIT=1 \
|
||||
PAGE_SIZE=4096
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cache_v7.o \
|
||||
$(LOCAL_DIR)/mmu.o \
|
||||
$(LOCAL_DIR)/fp.o \
|
||||
$(LOCAL_DIR)/cachedebug_a8.o
|
||||
|
||||
# Turned off to save space, enable as needed
|
||||
ifeq ($(APPLICATION),XXX_iBoot)
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cortex_hang.o \
|
||||
$(LOCAL_DIR)/cortex_debug.o
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# ARM Cortex A9
|
||||
#
|
||||
ifeq ($(ARM_CPU),cortex-a9)
|
||||
ARM_ARCH ?= armv7
|
||||
ARM_ARCH_OPTIONS := ARCH_ARMv7=1 WITH_VFP=1
|
||||
OPTIONS += \
|
||||
CPU_ARM_CORTEX_A9=1 \
|
||||
WITH_MMU=1 \
|
||||
WITH_MMU_SECURITY_EXTENSIONS=1 \
|
||||
WITH_CACHE=1 \
|
||||
CPU_CACHELINE_SIZE=32 \
|
||||
CPU_CACHELINE_SHIFT=5 \
|
||||
CPU_CACHEINDEX_SHIFT=8 \
|
||||
CPU_CACHESET_SHIFT=2 \
|
||||
WITH_BRANCH_PREDICTION=1 \
|
||||
WITH_UNALIGNED_MEM=1 \
|
||||
WITH_L1_PARITY=1 \
|
||||
SET_AUX_SMP_BIT=1 \
|
||||
PAGE_SIZE=4096
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cache_v7.o \
|
||||
$(LOCAL_DIR)/mmu.o \
|
||||
$(LOCAL_DIR)/fp.o
|
||||
endif
|
||||
|
||||
#
|
||||
# ARM Cortex A5 "Sparrow"
|
||||
#
|
||||
ifeq ($(ARM_CPU),cortex-a5)
|
||||
ARM_ARCH ?= armv7
|
||||
ARM_ARCH_OPTIONS := ARCH_ARMv7=1 WITH_VFP=1
|
||||
OPTIONS += \
|
||||
CPU_ARM_CORTEX_A5=1 \
|
||||
FP_REGISTER_COUNT=32 \
|
||||
WITH_MMU=1 \
|
||||
WITH_MMU_SECURITY_EXTENSIONS=1 \
|
||||
WITH_CACHE=1 \
|
||||
CPU_CACHELINE_SIZE=32 \
|
||||
CPU_CACHELINE_SHIFT=5 \
|
||||
CPU_CACHEINDEX_SHIFT=8 \
|
||||
CPU_CACHESET_SHIFT=2 \
|
||||
WITH_BRANCH_PREDICTION=1 \
|
||||
WITH_UNALIGNED_MEM=1 \
|
||||
SET_AUX_SMP_BIT=1 \
|
||||
PAGE_SIZE=4096
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cache_v7.o \
|
||||
$(LOCAL_DIR)/mmu.o \
|
||||
$(LOCAL_DIR)/fp.o
|
||||
endif
|
||||
|
||||
#
|
||||
# ARM Cortex A7 "Kingfisher"
|
||||
#
|
||||
ifeq ($(ARM_CPU),cortex-a7)
|
||||
ARM_ARCH ?= armv7k
|
||||
ARM_ARCH_OPTIONS := ARCH_ARMv7=1 WITH_VFP=1 WITH_VFP_ALWAYS_ON=1
|
||||
OPTIONS += \
|
||||
CPU_ARM_CORTEX_A7=1 \
|
||||
VFP_REV=4 \
|
||||
FP_REGISTER_COUNT=32 \
|
||||
WITH_MMU=1 \
|
||||
WITH_MMU_SECURITY_EXTENSIONS=1 \
|
||||
WITH_CACHE=1 \
|
||||
WITH_EARLY_ICACHE=1 \
|
||||
CPU_CACHELINE_SIZE=64 \
|
||||
CPU_CACHELINE_SHIFT=6 \
|
||||
CPU_CACHEINDEX_SHIFT=7 \
|
||||
CPU_CACHESET_SHIFT=2 \
|
||||
WITH_BRANCH_PREDICTION=1 \
|
||||
WITH_UNALIGNED_MEM=1 \
|
||||
WITH_ARCHITECTED_L2=1 \
|
||||
SET_AUX_SMP_BIT=1 \
|
||||
PAGE_SIZE=4096
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cache_v7.o \
|
||||
$(LOCAL_DIR)/mmu.o \
|
||||
$(LOCAL_DIR)/fp.o
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# General and conditional configuration
|
||||
################################################################################
|
||||
|
||||
# sanity check
|
||||
ifeq ($(ARM_ARCH),)
|
||||
$(error ARM_ARCH not set, no valid CPU selected)
|
||||
endif
|
||||
|
||||
# build for the proper cpu
|
||||
OPTIONS += ARCH_ARM=1
|
||||
GLOBAL_ALLFLAGS += -arch $(ARM_ARCH) $(addprefix -D,$(ARM_ARCH_OPTIONS))
|
||||
GLOBAL_LDFLAGS += -arch $(ARM_ARCH)
|
||||
|
||||
# Tell the build system how libraries should be tagged
|
||||
LIBRARY_TAG += $(ARM_ARCH)
|
||||
LIBRARY_OPTIONS += ARCH=arm ARM_ARCH=$(ARM_ARCH)
|
||||
|
||||
# Always build libbuiltin, to partially override the gcc static library.
|
||||
LIBRARY_MODULES += lib/libbuiltin
|
||||
|
||||
# set up to build with thumb
|
||||
WITH_THUMB ?= true
|
||||
ifeq ($(WITH_THUMB),true)
|
||||
THUMBFLAGS := -mthumb
|
||||
LIBRARY_TAG += thumb
|
||||
else
|
||||
THUMBFLAGS := -mno-thumb
|
||||
LIBRARY_TAG += arm
|
||||
endif
|
||||
|
||||
GLOBAL_ALLFLAGS += $(THUMBFLAGS)
|
||||
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
|
||||
|
||||
# Defaults for stack sizes
|
||||
# These are override in platform/.../rules.mk
|
||||
ifeq ($(IRQ_STACK_SIZE),)
|
||||
IRQ_STACK_SIZE ?= 2048
|
||||
endif
|
||||
ifeq ($(FIQ_STACK_SIZE),)
|
||||
FIQ_STACK_SIZE ?= 1024
|
||||
endif
|
||||
ifeq ($(EXCEPTION_STACK_SIZE),)
|
||||
EXCEPTION_STACK_SIZE ?= 2048
|
||||
endif
|
||||
ifeq ($(BOOTSTRAP_STACK_SIZE),)
|
||||
BOOTSTRAP_STACK_SIZE ?= 2048
|
||||
endif
|
||||
OPTIONS += \
|
||||
IRQ_STACK_SIZE=$(IRQ_STACK_SIZE) \
|
||||
FIQ_STACK_SIZE=$(FIQ_STACK_SIZE) \
|
||||
EXCEPTION_STACK_SIZE=$(EXCEPTION_STACK_SIZE) \
|
||||
BOOTSTRAP_STACK_SIZE=$(BOOTSTRAP_STACK_SIZE)
|
||||
|
||||
# Force start.o and asm.o to link first
|
||||
ALL_OBJS := \
|
||||
$(LOCAL_DIR)/start.o \
|
||||
$(LOCAL_DIR)/asm.o \
|
||||
$(ALL_OBJS)
|
||||
|
||||
# Code common to all cores
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/cpu.o \
|
||||
$(LOCAL_DIR)/context.o \
|
||||
$(LOCAL_DIR)/entropy.o \
|
||||
$(LOCAL_DIR)/exceptions.o \
|
||||
$(LOCAL_DIR)/handlers.o \
|
||||
$(LOCAL_DIR)/task.o
|
||||
|
||||
LINKER_EXPORTS := $(LOCAL_DIR)/link.exp
|
||||
|
||||
# if someone requests DCC, add it in
|
||||
ifeq ($(WITH_DCC),true)
|
||||
OPTIONS += ARM_DCC_SYNCHRONOUS=1
|
||||
include $(LOCAL_DIR)/dcc/rules.mk
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2014 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <platform/memmap.h>
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.no_dead_strip _start
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
b __reset
|
||||
|
||||
ldr pc, vectoraddr + 4
|
||||
ldr pc, vectoraddr + 8
|
||||
ldr pc, vectoraddr + 12
|
||||
ldr pc, vectoraddr + 16
|
||||
ldr pc, vectoraddr + 20
|
||||
ldr pc, vectoraddr + 24
|
||||
ldr pc, vectoraddr + 28
|
||||
|
||||
vectoraddr:
|
||||
.word __reset
|
||||
.word ___arm_undefined
|
||||
.word ___arm_syscall
|
||||
.word ___arm_prefetch_abort
|
||||
.word ___arm_data_abort
|
||||
.word ___arm_reserved
|
||||
.word ___arm_irq
|
||||
.word ___arm_fiq
|
||||
|
||||
__reset:
|
||||
/*
|
||||
* Test the running versus desired the start of the text
|
||||
* to determine if relocaiton is required
|
||||
*/
|
||||
adr r0, _start
|
||||
ldr r1, L_TEXT_START
|
||||
cmp r0, r1
|
||||
|
||||
#ifdef PLATFORM_START_FUNCTION
|
||||
/*
|
||||
* r0 and r1 must be preserved
|
||||
* 'eq' will be true if no text relocation is required
|
||||
*/
|
||||
bl PLATFORM_START_FUNCTION
|
||||
#endif
|
||||
|
||||
/* re-test the running start versus desired start of the text */
|
||||
cmp r0, r1
|
||||
beq __do_relocate_data
|
||||
|
||||
/* relocate to the desired text location and branch to it */
|
||||
ldr r2, L_TEXT_END
|
||||
sub r2, r2, r1
|
||||
__relocate_loop:
|
||||
subs r2, r2, #4
|
||||
ldr r3, [r0, r2]
|
||||
str r3, [r1, r2]
|
||||
bne __relocate_loop
|
||||
|
||||
#if ARCH_ARMv7
|
||||
/* prevent speculation to the desired text location */
|
||||
dsb
|
||||
isb
|
||||
#endif
|
||||
|
||||
/* branch into the desired text location */
|
||||
bx r1
|
||||
|
||||
/* test if the data if needs to be relocated */
|
||||
__do_relocate_data:
|
||||
ldr r0, L_DATA_RO_START
|
||||
mov r1, #0x00001000 // Round up to a 4K page
|
||||
sub r1, r1, #1 //
|
||||
add r0, r0, r1 //
|
||||
bic r0, r0, r1 //
|
||||
ldr r1, L_DATA_START
|
||||
cmp r0, r1
|
||||
beq __stacksetup
|
||||
|
||||
/* relocate the data */
|
||||
ldr r2, L_DATA_END
|
||||
sub r2, r2, r1
|
||||
__relocate_data_loop:
|
||||
subs r2, r2, #4
|
||||
ldr r3, [r0, r2]
|
||||
str r3, [r1, r2]
|
||||
bne __relocate_data_loop
|
||||
|
||||
__stacksetup:
|
||||
/* set up the stack for irq, fiq, abort, undefined, and lastly supervisor mode */
|
||||
mrs r0, cpsr
|
||||
bic r0, r0, #0x1f
|
||||
|
||||
orr r1, r0, #0x12 // irq
|
||||
msr cpsr_c, r1
|
||||
mov lr, #0
|
||||
ldr sp, _irq_stack_top
|
||||
|
||||
orr r1, r0, #0x11 // fiq
|
||||
msr cpsr_c, r1
|
||||
mov lr, #0
|
||||
ldr sp, _fiq_stack_top
|
||||
|
||||
orr r1, r0, #0x17 // abort
|
||||
msr cpsr_c, r1
|
||||
mov lr, #0
|
||||
ldr sp, _exc_stack_top
|
||||
|
||||
orr r1, r0, #0x1b // undefined
|
||||
msr cpsr_c, r1
|
||||
mov lr, #0
|
||||
ldr sp, _exc_stack_top
|
||||
|
||||
orr r1, r0, #0x13 // supervisor
|
||||
msr cpsr_c, r1
|
||||
ldr sp, _svc_stack_top
|
||||
|
||||
#if ARCH_ARMv7
|
||||
mrs r1, cpsr
|
||||
bic r1, #0x100 // enable imprecise data aborts
|
||||
msr cpsr_x, r1
|
||||
#endif
|
||||
|
||||
#if SUPPORT_SLEEP
|
||||
/* look at the global wakeup flag, avoid clearing the BSS and go straight to wake up */
|
||||
.global _platform_wakeup
|
||||
ldr r1, _arch_sleep_magic /* will be zero on the wake path, nonzero otherwise */
|
||||
eor r0, r0, r0
|
||||
cmp r0, r1
|
||||
bne __do_bss
|
||||
ldr r0, L__platform_wakeup
|
||||
mov lr, pc
|
||||
bx r0
|
||||
#endif
|
||||
|
||||
__do_bss:
|
||||
/* clear the bss section */
|
||||
ldr r0, L_BSS_START
|
||||
ldr r1, L_BSS_END
|
||||
mov r2, #0
|
||||
mov r3, #0
|
||||
mov r4, #0
|
||||
mov r5, #0
|
||||
mov r6, #0
|
||||
mov r7, #0
|
||||
mov r8, #0
|
||||
mov r10, #0
|
||||
sub r12, r1, r0
|
||||
/* If there are less than 256 bytes, skip this loop */
|
||||
subs r12, r12, #256
|
||||
blo __bss_lessthan256
|
||||
|
||||
__bss_loop256:
|
||||
/* Clear 256 bytes at a time */
|
||||
subs r12, #256
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
stmia r0!, {r2-r8, r10}
|
||||
bge __bss_loop256
|
||||
|
||||
__bss_lessthan256:
|
||||
/* If are less than 32 bytes left to handle, skip this loop */
|
||||
adds r12, r12, #(256 - 32)
|
||||
bcc __bss_lessthan32
|
||||
|
||||
__bss_loop32:
|
||||
/* Clear 32 bytes at a time */
|
||||
subs r12, r12, #32
|
||||
stmia r0!, {r2-r8, r10}
|
||||
bge __bss_loop32
|
||||
|
||||
__bss_lessthan32:
|
||||
/* If there's nothing left to go, skip this loop */
|
||||
adds r12, r12, #32
|
||||
beq __bss_done
|
||||
|
||||
__bss_loop4:
|
||||
/* Clear 4 bytes at a time */
|
||||
subs r12, r12, #4
|
||||
str r2, [r0],#4
|
||||
bgt __bss_loop4
|
||||
|
||||
__bss_done:
|
||||
/* branch to main */
|
||||
ldr r0, L__main
|
||||
mov lr, pc
|
||||
bx r0
|
||||
b .
|
||||
|
||||
|
||||
.org 0x200
|
||||
L__build_banner_string:
|
||||
.ascii CONFIG_PROGNAME_STRING
|
||||
.ascii " for "
|
||||
.ascii CONFIG_BOARD_STRING
|
||||
.ascii ", Copyright 2007-2016, Apple Inc."
|
||||
|
||||
.org 0x240
|
||||
L__build_style_string:
|
||||
.ascii BUILD_STYLE
|
||||
|
||||
/* This will get replaced by macho_post_process.py so that the build tag
|
||||
is accurate even for iterative desktop builds that don't rebuild start.o */
|
||||
.org 0x280
|
||||
_build_tag_string_contents:
|
||||
|
||||
/* Placeholder for macho_post_process.py. Placing the UUID here allows
|
||||
debuggers to locate the UUID based on the address of the vectors */
|
||||
.org 0x300
|
||||
_UUID:
|
||||
.space 0x20
|
||||
|
||||
.global _build_banner_string
|
||||
_build_banner_string:
|
||||
.long L__build_banner_string
|
||||
|
||||
.global _build_style_string
|
||||
_build_style_string:
|
||||
.long L__build_style_string
|
||||
|
||||
.global _build_tag_string
|
||||
_build_tag_string:
|
||||
.long _build_tag_string_contents
|
||||
|
||||
L__main:
|
||||
.long __main
|
||||
|
||||
/* linked start and end addresses of the text */
|
||||
L_TEXT_START:
|
||||
.long (TEXT_BASE)
|
||||
L_TEXT_END:
|
||||
.long section$start$__DATA$__zerofill
|
||||
|
||||
/* start address of the data in the read only text */
|
||||
L_DATA_RO_START:
|
||||
.long segment$end$__TEXT
|
||||
|
||||
/* linked start and end addresses of the data */
|
||||
L_DATA_START:
|
||||
.long segment$start$__DATA
|
||||
L_DATA_END:
|
||||
.long section$start$__DATA$__zerofill
|
||||
|
||||
/* linked start and end addresses of the zero-filled range */
|
||||
L_BSS_START:
|
||||
.long section$start$__DATA$__zerofill
|
||||
L_BSS_END:
|
||||
.long segment$end$__DATA
|
||||
|
||||
/*
|
||||
* Stacks.
|
||||
*
|
||||
* The following stacks must be defined:
|
||||
*
|
||||
* bootstrap stack
|
||||
* Used as the stack for the initial thread.
|
||||
*
|
||||
* exception stack
|
||||
* Used when handling exceptions other than interrupts.
|
||||
*
|
||||
* interrupt stack
|
||||
* Used when handling regular interrupts.
|
||||
*
|
||||
* fiq stack
|
||||
* Used when handling FIQ interrupts.
|
||||
*/
|
||||
|
||||
.global _irq_stack_top
|
||||
.global _fiq_stack_top
|
||||
.global _exc_stack_top
|
||||
.global _svc_stack_top
|
||||
|
||||
#ifndef STACK_SIZE
|
||||
/*
|
||||
* This is a bit hokey, as the platform doesn't really know
|
||||
* what the bootstrap stack size should be.
|
||||
*/
|
||||
# define STACK_SIZE BOOTSTRAP_STACK_SIZE
|
||||
#endif
|
||||
#if APPLICATION_EMBEDDEDIOP
|
||||
/*
|
||||
* Locally-allocated stacks.
|
||||
*/
|
||||
_irq_stack_top:
|
||||
.long irq_stack + IRQ_STACK_SIZE
|
||||
_fiq_stack_top:
|
||||
.long fiq_stack + FIQ_STACK_SIZE
|
||||
_exc_stack_top:
|
||||
.long exc_stack + EXCEPTION_STACK_SIZE
|
||||
_svc_stack_top:
|
||||
.long svc_stack + STACK_SIZE
|
||||
|
||||
/* allocate stacks here */
|
||||
.lcomm irq_stack, IRQ_STACK_SIZE, 4
|
||||
.lcomm fiq_stack, FIQ_STACK_SIZE, 4
|
||||
.lcomm exc_stack, EXCEPTION_STACK_SIZE, 4
|
||||
.lcomm svc_stack, STACK_SIZE, 4
|
||||
|
||||
#elif defined(STACK_BASE)
|
||||
/*
|
||||
* Simple stack layout with just one allocation in STACK_BASE/STACK_SIZE
|
||||
* supplied by the platform definition.
|
||||
*
|
||||
* Bootstrap stack starts at the top of the allocation,
|
||||
* exception stack and interrupt stack share the same
|
||||
* chunk at the bottom.
|
||||
*/
|
||||
_fiq_stack_top:
|
||||
.long STACK_BASE + FIQ_STACK_SIZE
|
||||
_exc_stack_top:
|
||||
_irq_stack_top:
|
||||
.long STACK_BASE + IRQ_STACK_SIZE
|
||||
_svc_stack_top:
|
||||
.long STACK_BASE + STACK_SIZE
|
||||
#else
|
||||
# error No stack defined
|
||||
#endif
|
||||
|
||||
#if SUPPORT_SLEEP
|
||||
.global _arch_sleep_magic
|
||||
_arch_sleep_magic:
|
||||
.long 0xffffffff
|
||||
|
||||
L__platform_wakeup:
|
||||
.long _platform_wakeup
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys.h>
|
||||
#include <sys/task.h>
|
||||
|
||||
static void arch_task_trampoline(void) __noreturn;
|
||||
|
||||
static void
|
||||
arch_task_trampoline(void)
|
||||
{
|
||||
/* exit the critical section we implicitly started with */
|
||||
exit_critical_section();
|
||||
|
||||
dprintf(DEBUG_SPEW, "arch_task_trampoline: task %p (%s) routine %p, arg %p\n",
|
||||
current_task, current_task->name, current_task->routine, current_task->arg);
|
||||
|
||||
/* call the start routine */
|
||||
int ret = current_task->routine(current_task->arg);
|
||||
|
||||
dprintf(DEBUG_SPEW, "arch_task_trampoline: task %p (%s) exits with %d\n",
|
||||
current_task, current_task->name, ret);
|
||||
|
||||
task_exit(ret);
|
||||
|
||||
/* never return */
|
||||
}
|
||||
|
||||
int
|
||||
arch_task_create(struct task *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < 10; i++)
|
||||
t->arch.regs[i] = 0;
|
||||
|
||||
/* set the default starting point to be arch_task_trampoline */
|
||||
t->arch.regs[ARM_ARCH_TASK_LR] = (uint32_t)&arch_task_trampoline;
|
||||
/* the ARM describes some encodings of SP ops (pre/post increment and/or decrement) as
|
||||
potentially reaching above the SP by a word. Our toolchain might not emit such encodings,
|
||||
but we'd rather be safe than sorry. Originally, we took off 4 bytes, but
|
||||
to better align the stacks for some of the newer ABIs (e.g. armv7k), we'll consistently
|
||||
take off 16 bytes from the top of the stack */
|
||||
t->arch.regs[ARM_ARCH_TASK_SP] = (uint32_t)t->stack_base + t->stack_len - 16;
|
||||
t->arch.regs[ARM_ARCH_TASK_FP] = 0;
|
||||
|
||||
#if WITH_VFP
|
||||
t->arch.fpexc = 0; /* default state is FP disabled */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user