first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+276
View File
@@ -0,0 +1,276 @@
/*
* Copyright (c) 2011-2012, 2014 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/arm64/proc_reg.h>
.text
.align 2
.globl _arm_read_sctlr
_arm_read_sctlr:
mrs x0, SCTLR_ELx
ret
.text
.align 2
.globl _arm_write_sctlr
_arm_write_sctlr:
msr SCTLR_ELx, x0
dsb sy
isb sy
// The ifdef should match the ifdef in arch_cpu_quiesce()
#if CPU_APPLE_CYCLONE
// Don't allow MMU or WXN to be disabled. Placing the check after the msr
// means that a ROP attack will fail unless an attacker can trigger an
// interrupt between the msr and check
mov x1, x0
orr x0, x0, #SCTLR_M_ENABLED
orr x0, x0, #SCTLR_WXN_ENABLED
cmp x0, x1
b.ne _arm_write_sctlr
#endif
ret
#if WITH_EL3
.text
.align 2
.globl _arm_write_scr
_arm_write_scr:
msr SCR_EL3, x0
isb sy
ret
#endif
#if WITH_L2_AS_RAM
.text
.align 2
.globl _arm_read_l2_cramconfig
_arm_read_l2_cramconfig:
mrs x0, s3_3_c15_c7_0
ret
#endif
.text
.align 2
.globl _arm_write_mair
_arm_write_mair:
msr MAIR_ELx, x0
isb sy
ret
.text
.align 2
.globl _arm_write_tcr
_arm_write_tcr:
msr TCR_ELx, x0
isb sy
ret
.text
.align 2
.globl _arm_write_ttbr0
_arm_write_ttbr0:
msr TTBR0_ELx, x0
isb sy
ret
.text
.align 2
.globl _arm_read_cpacr
_arm_read_cpacr:
mrs x0, CPACR_EL1
ret
.text
.align 2
.globl _arm_write_cpacr
_arm_write_cpacr:
msr CPACR_EL1, x0
isb sy
ret
.text
.align 2
.globl _arm_read_cntp_ctl
_arm_read_cntp_ctl:
isb sy
mrs x0, CNTP_CTL_EL0
ret
.text
.align 2
.globl _arm_write_cntp_ctl
_arm_write_cntp_ctl:
msr CNTP_CTL_EL0, x0
isb sy
ret
.text
.align 2
.globl _arm_read_cntpct
_arm_read_cntpct:
isb sy
mrs x0, CNTPCT_EL0
ret
.text
.align 2
.globl _arm_write_cntp_tval
_arm_write_cntp_tval:
msr CNTP_TVAL_EL0, x0
isb sy
ret
.text
.align 2
.globl _arm_flush_tlbs
_arm_flush_tlbs:
dsb sy
#if WITH_EL3
tlbi alle3
#else
tlbi vmalle1
#endif
dsb sy
isb sy
ret
.text
.align 2
.globl _arm_invalidate_icache
_arm_invalidate_icache:
ic iallu
dsb sy
isb sy
ret
.text
.align 2
.globl _arm_invalidate_dcache_line
_arm_invalidate_dcache_line:
ret
.text
.align 2
.globl _arm_clean_dcache_line
_arm_clean_dcache_line:
ret
.text
.align 2
.globl _arm_clean_invalidate_dcache
_arm_clean_invalidate_dcache:
ret
.text
.align 2
.globl _arm_clean_dcache
_arm_clean_dcache:
ret
.text
.align 2
.globl _arm_invalidate_dcache
_arm_invalidate_dcache:
ret
.text
.align 2
.globl _arm_clean_invalidate_dcache_line
_arm_clean_invalidate_dcache_line:
dc civac, x0
ret
.text
.align 2
.globl _arm_drain_write_buffer
_arm_drain_write_buffer:
ret
.text
.align 2
.globl _arm_memory_barrier
_arm_memory_barrier:
dmb sy
ret
.text
.align 2
.globl _arm_vtop
_arm_vtop:
mrs x2, DAIF // Load current DAIF
msr DAIFSet, #(DAIFSC_IRQF | DAIFSC_FIQF) // Disable IRQ
isb sy
mov x9, x0 // Saved address
at s1e3r, x0 // Translation Stage 1 EL1
isb sy
mrs x1, PAR_EL1 // Read result
tst x1, #1 // Test Translation not valid
cset x0, eq
b.ne L_arm_vtop_ret
movk x3, #0xf000
movk x3, #0xffff, lsl #16
movk x3, #0xffff, lsl #32
and x1, x1, x3 // Get physical address base
and x0, x9, #0xfff
orr x0, x1, x0 // Add page offset
L_arm_vtop_ret:
msr DAIF, x2 // Restore interrupt state, return
isb sy
ret
.text
.align 2
.globl _arm_disable_async_aborts
_arm_disable_async_aborts:
msr DAIFSet, #(DAIFSC_ASYNCF)
isb sy
ret
.text
.align 2
.globl _arm_enable_async_aborts
_arm_enable_async_aborts:
msr DAIFClr, #(DAIFSC_ASYNCF)
isb sy
ret
.text
.align 2
.globl _arch_disable_ints
_arch_disable_ints:
msr DAIFSet, #(DAIFSC_IRQF | DAIFSC_FIQF)
isb sy
ret
.text
.align 2
.globl _arch_enable_ints
_arch_enable_ints:
msr DAIFClr, #(DAIFSC_IRQF | DAIFSC_FIQF)
isb sy
ret
.text
.align 2
.globl _arch_halt
_arch_halt:
dsb sy
isb sy
wfi
ret
.text
.align 2
.globl _arch_spin
_arch_spin:
hint 0x45 // make fastsim drop to debugger (nop on hardware)
b .
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2011-2012 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.
*/
/*
* Task context switch support.
*
*/
/*
* Code here must remain synchronized with the structure and offsets defined in arch_task.h:
*
* struct arch_task {
* uint64_t regs[29]; // x0-x28
* uint64_t fp;
* uint64_t lr;
* uint64_t sp;
*
* union {
* uint128_t q;
* uint64_t d;
* uint32_t s;
* } vregs[32]; // v0-v31
* uint32_t fpsr;
* uint32_t fpcr;
* };
*/
/* AAPCS-64 5.1.1 Page 13:
* Preserve r16-17, r19-r28, FP, and SP.
*
* AAPCS-64 5.1.2 Page 14:
* Registers d8-d15 (s8-s15) must be preserved by a callee across subroutine
* calls; the remaining registers (v0-v7, v16-v31) do not need to be preserved
* (or should be preserved by the caller).
*/
/*
* void arch_task_context_switch(struct arch_task *old, struct arch_task *new_task);
*/
.text
.align 2
.globl _arch_task_context_switch
_arch_task_context_switch:
stp x16, x17, [x0, #120]
stp x19, x20, [x0, #152]
stp x21, x22, [x0, #168]
stp x23, x24, [x0, #184]
stp x25, x26, [x0, #200]
stp x27, x28, [x0, #216]
stp fp, lr, [x0, #232]
mov x2, sp
str x2, [x0, #248]
#if WITH_VFP
str d8, [x0, #384]
str d9, [x0, #400]
str d10, [x0, #416]
str d11, [x0, #432]
str d12, [x0, #448]
str d13, [x0, #464]
str d14, [x0, #480]
str d15, [x0, #496]
#endif
mov x0, x1
b _arch_task_context_restore
/*
* void arch_task_context_restore(struct arch_task *restore_context)
*/
.text
.align 2
.globl _arch_task_context_restore
_arch_task_context_restore:
ldp x16, x17, [x0, #120]
ldp x19, x20, [x0, #152]
ldp x21, x22, [x0, #168]
ldp x23, x24, [x0, #184]
ldp x25, x26, [x0, #200]
ldp x27, x28, [x0, #216]
ldp fp, lr, [x0, #232]
ldr x1, [x0, #248]
mov sp, x1
#if WITH_VFP
ldr d8, [x0, #384]
ldr d9, [x0, #400]
ldr d10, [x0, #416]
ldr d11, [x0, #432]
ldr d12, [x0, #448]
ldr d13, [x0, #464]
ldr d14, [x0, #480]
ldr d15, [x0, #496]
#endif
ret
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2011-2012, 2014 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.h>
#include <arch/arm/arm.h>
#include <arch/arm64/proc_reg.h>
#include <debug.h>
#include <platform.h>
#include <platform/memmap.h>
extern void arm_write_sctlr(uint64_t);
extern uint64_t arm_read_sctlr();
extern void arm_enable_async_aborts();
#if WITH_EL3
extern void arm_write_scr(uint64_t);
#endif
int arch_cpu_init(bool resume)
{
uint64_t sctlr;
#if WITH_EL3
uint64_t scr;
/* enable interrupts forwarding to EL3 */
scr = (SCR_EA | SCR_FIQ | SCR_IRQ);
arm_write_scr(scr);
#endif
/* enable async aborts */
arm_enable_async_aborts();
/* invalidate caches */
arm_invalidate_icache();
arm_invalidate_dcache();
sctlr = arm_read_sctlr();
/* turn on Stack Alignment check */
sctlr |= SCTLR_SA_ENABLED;
/* turn on the mmu */
arm_mmu_init(resume);
sctlr |= SCTLR_M_ENABLED;
/* disallow executing from writeable pages */
sctlr |= SCTLR_WXN_ENABLED;
/* turn on d-cache */
sctlr |= SCTLR_D_ENABLED;
/* turn on i-cache */
sctlr |= SCTLR_I_ENABLED;
/* enable the MMU, caches and etc. */
arm_write_sctlr(sctlr);
#if WITH_VFP
/* initialize VFP */
arm_fp_init();
#endif
return 0;
}
int arch_cpu_quiesce(void)
{
#if !CPU_APPLE_CYCLONE
uint64_t sctlr;
/* clean the d-cache */
arm_clean_dcache();
/* read the control regiser base value */
sctlr = arm_read_sctlr();
sctlr &= ~(SCTLR_D_ENABLED | SCTLR_SA_ENABLED | SCTLR_I_ENABLED | SCTLR_M_ENABLED | SCTLR_WXN_ENABLED);
/* disable the MMU, caches and etc. */
arm_write_sctlr(sctlr);
/* invalidate i-cache */
arm_invalidate_icache();
#endif /* !CPU_APPLE_CYCLONE */
return 0;
}
int arch_cpu_init_posttasks(void)
{
return 0;
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2012 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
.balign 4
.globl _arch_get_entropy
// 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.
//
_arch_get_entropy:
mov x1, x0
mov w0, #0
mov w2, #32
1:
mov w3, w2
2:
subs w3, w3, #1
b.ne 2b
ldr w3, [x1]
and w3, w3, #1
orr w0, w3, w0, lsl #1
subs w2, w2, #1
b.ne 1b
ret
+306
View File
@@ -0,0 +1,306 @@
/*
* Copyright (C) 2011-2012, 2014 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.
*/
#if WITH_EL3
#error "This file should not be built for platforms WITH_EL3"
#endif
////////////////////////////////////////////////////////////
// This is what exception frame looks like:
//
// 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;
// uint64_t reserved2; // stp requires multiple of 16 in imm field
// uint64_t reserved3; // stp requires multiple of 16 in imm field
// union {
// uint128_t q;
// uint64_t d;
// uint32_t s;
// } vregs[32]; // v0-v31
// uint32_t fpsr;
// uint32_t reserved4;
// uint32_t fpcr;
// uint32_t reserved5;
// };
////////////////////////////////////////////////////////////
.macro EL1_SP0_VECTOR
msr SPSel, #0 // Switch to SP0
sub sp, sp, #832 // Create exception frame
stp x0, x1, [sp, #0] // Save x0, x1 to exception frame
add x0, sp, #832 // Calculate the original stack pointer
str x0, [sp, #248] // Save stack pointer to exception frame
stp fp, lr, [sp, #232] // Save fp and lr to exception frame
mrs lr, ELR_EL1 // Get exception link reg so _dispatch64 can make a frame
mov x0, sp // Copy saved state pointer to x0
.endmacro
.macro FASTSIM_DEBUG_HINT
hint 0x45 // make fastsim drop to debugger (nop on hardware)
.endmacro
.text
.align 12
.globl _exception_vector_base
_exception_vector_base:
L__el1_sp0_synchronous_vector:
EL1_SP0_VECTOR
mrs x1, ESR_EL1 // Load exception syndrome
str x1, [x0, #280]
mrs x1, FAR_EL1 // Load fault address
str x1, [x0, #272]
adrp x1, _arm_synchronous_exception@page
add x1, x1, _arm_synchronous_exception@pageoff
b __dispatch64
.text
.align 7
L__el1_sp0_irq_vector:
EL1_SP0_VECTOR
adrp x1, _interrupt_stack_top@page
add x1, x1, _interrupt_stack_top@pageoff
ldr x1, [x1]
mov sp, x1
adrp x1, _arm_irq@page
add x1, x1, _arm_irq@pageoff
b __dispatch64
.text
.align 7
L__el1_sp0_fiq_vector:
EL1_SP0_VECTOR
adrp x1, _interrupt_stack_top@page
add x1, x1, _interrupt_stack_top@pageoff
ldr x1, [x1]
mov sp, x1
adrp x1, _arm_fiq@page
add x1, x1, _arm_fiq@pageoff
b __dispatch64
.text
.align 7
L__el1_sp0_serror_vector:
EL1_SP0_VECTOR
mrs x1, ESR_EL1 // Load exception syndrome
str x1, [x0, #280]
mrs x1, FAR_EL1 // Load fault address
str x1, [x0, #272]
adrp x1, _arm_serror_exception@page
add x1, x1, _arm_serror_exception@pageoff
b __dispatch64
.text
.align 7
L__el1_sp1_synchronous_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el1_sp1_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el1_sp1_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el1_sp1_serror_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_synchronous_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_serror_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_synchronous_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_serror_vector:
FASTSIM_DEBUG_HINT
b .
/* Placeholder for macho_post_process.py. Placing the UUID here
allows debuggers to locate the UUID based on the value of VBAR */
.text
.align 7
_UUID:
.space 32
/* 64-bit first level exception handler dispatcher.
* Completes register context saving and branches to FLEH.
* Expects:
* {x0, x1, fp, lr, sp} - saved
* x0 - arm_context_t
* x1 - address of FLEH
* fp - previous stack frame if EL1
* lr - unused
* sp - kernel stack
*/
.text
.align 2
__dispatch64:
stp fp, lr, [sp, #-16]! // Create a frame to help debuggers unwind
mov fp, sp // past the exception handler
stp x2, x3, [x0, #16] // Save remaining GPRs
stp x4, x5, [x0, #32]
stp x6, x7, [x0, #48]
stp x8, x9, [x0, #64]
stp x10, x11, [x0, #80]
stp x12, x13, [x0, #96]
stp x14, x15, [x0, #112]
stp x16, x17, [x0, #128]
stp x18, x19, [x0, #144]
stp x20, x21, [x0, #160]
stp x22, x23, [x0, #176]
stp x24, x25, [x0, #192]
stp x26, x27, [x0, #208]
str x28, [x0, #224]
mrs lr, ELR_EL1 // Get exception link register
str lr, [x0, #264] // Save ELR to PCB
mrs x2, SPSR_EL1 // Get CPSR
str w2, [x0, #256] // Save CPSR to PCB
#if WITH_VFP
stp q0, q1, [x0, #304]
stp q2, q3, [x0, #336]
stp q4, q5, [x0, #368]
stp q6, q7, [x0, #400]
stp q8, q9, [x0, #432]
stp q10, q11, [x0, #464]
stp q12, q13, [x0, #496]
stp q14, q15, [x0, #528]
stp q16, q17, [x0, #560]
stp q18, q19, [x0, #592]
stp q20, q21, [x0, #624]
stp q22, q23, [x0, #656]
stp q24, q25, [x0, #688]
stp q26, q27, [x0, #720]
stp q28, q29, [x0, #752]
stp q30, q31, [x0, #784]
mrs x2, FPSR
str w2, [x0, #816]
mrs x2, FPCR
str w2, [x0, #820]
#endif
mov x21, x0 // Copy arm_context_t pointer to x21
blr x1
b __exception_return
.text
.align 2
__exception_return:
mov sp, x21 // Reload the arm_context_t pointer
#if WITH_VFP
ldp q0, q1, [sp, #304]
ldp q2, q3, [sp, #336]
ldp q4, q5, [sp, #368]
ldp q6, q7, [sp, #400]
ldp q8, q9, [sp, #432]
ldp q10, q11, [sp, #464]
ldp q12, q13, [sp, #496]
ldp q14, q15, [sp, #528]
ldp q16, q17, [sp, #560]
ldp q18, q19, [sp, #592]
ldp q20, q21, [sp, #624]
ldp q22, q23, [sp, #656]
ldp q24, q25, [sp, #688]
ldp q26, q27, [sp, #720]
ldp q28, q29, [sp, #752]
ldp q30, q31, [sp, #784]
ldr w3, [sp, #816]
msr FPSR, x3
ldr w4, [sp, #820]
msr FPCR, x4
#endif
ldr x0, [sp, #264] // Get the return address
msr ELR_EL1, x0 // Load the return address into ELR
ldr w1, [sp, #256] // Get the return CPSR
msr SPSR_EL1, x1 // Load the return CPSR into SPSR
ldp x0, x1, [sp, #0] // Restore the GPRs
ldp x2, x3, [sp, #16]
ldp x4, x5, [sp, #32]
ldp x6, x7, [sp, #48]
ldp x8, x9, [sp, #64]
ldp x10, x11, [sp, #80]
ldp x12, x13, [sp, #96]
ldp x14, x15, [sp, #112]
ldp x16, x17, [sp, #128]
ldp x18, x19, [sp, #144]
ldp x20, x21, [sp, #160]
ldp x22, x23, [sp, #176]
ldp x24, x25, [sp, #192]
ldp x26, x27, [sp, #208]
ldr x28, [sp, #224]
ldp fp, lr, [sp, #232]
/* Use exception stack to restore SP0 */
msr SPSel, #1 // Switch to SPx
stp x0, x1, [sp, #-16]! // Save x0 and x1
mrs x0, SP_EL0 // Reload the pcb pointer from SP0
ldr x1, [x0, #248] // Get the saved SP from the pcb
msr SP_EL0, x1 // Restore SP0
ldp x0, x1, [sp], #16 // Restore x0 and x1
eret
+315
View File
@@ -0,0 +1,315 @@
/*
* Copyright (C) 2011-2012, 2014 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.
*/
#if !WITH_EL3
#error "This file should only be built for platforms WITH_EL3"
#endif
////////////////////////////////////////////////////////////
// This is what exception frame looks like:
//
// 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;
// uint64_t reserved2; // stp requires multiple of 16 in imm field
// uint64_t reserved3; // stp requires multiple of 16 in imm field
// union {
// uint128_t q;
// uint64_t d;
// uint32_t s;
// } vregs[32]; // v0-v31
// uint32_t fpsr;
// uint32_t reserved4;
// uint32_t fpcr;
// uint32_t reserved5;
// };
////////////////////////////////////////////////////////////
.macro EL3_SP0_VECTOR
msr SPSel, #0 // Switch to SP0
sub sp, sp, #832 // Create exception frame
stp x0, x1, [sp, #0] // Save x0, x1 to exception frame
add x0, sp, #832 // Calculate the original stack pointer
str x0, [sp, #248] // Save stack pointer to exception frame
stp fp, lr, [sp, #232] // Save fp and lr to exception frame
mrs lr, ELR_EL3 // Get exception link reg so _dispatch64 can make a frame
mov x0, sp // Copy saved state pointer to x0
.endmacro
.macro FASTSIM_DEBUG_HINT
hint 0x45 // make fastsim drop to debugger (nop on hardware)
.endmacro
.text
.align 12
.globl _exception_vector_base
_exception_vector_base:
L__el3_sp0_synchronous_vector:
EL3_SP0_VECTOR
mrs x1, ESR_EL3 // Load exception syndrome
str x1, [x0, #280]
mrs x1, FAR_EL3 // Load fault address
str x1, [x0, #272]
adrp x1, _arm_synchronous_exception@page
add x1, x1, _arm_synchronous_exception@pageoff
b __dispatch64
.text
.align 7
L__el3_sp0_irq_vector:
EL3_SP0_VECTOR
adrp x1, _interrupt_stack_top@page
add x1, x1, _interrupt_stack_top@pageoff
ldr x1, [x1]
mov sp, x1
adrp x1, _arm_irq@page
add x1, x1, _arm_irq@pageoff
b __dispatch64
.text
.align 7
L__el3_sp0_fiq_vector:
EL3_SP0_VECTOR
adrp x1, _interrupt_stack_top@page
add x1, x1, _interrupt_stack_top@pageoff
ldr x1, [x1]
mov sp, x1
adrp x1, _arm_fiq@page
add x1, x1, _arm_fiq@pageoff
b __dispatch64
.text
.align 7
L__el3_sp0_serror_vector:
EL3_SP0_VECTOR
mrs x1, ESR_EL3 // Load exception syndrome
str x1, [x0, #280]
mrs x1, FAR_EL3 // Load fault address
str x1, [x0, #272]
adrp x1, _arm_serror_exception@page
add x1, x1, _arm_serror_exception@pageoff
b __dispatch64
.text
.align 7
L__el3_sp3_synchronous_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el3_sp3_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el3_sp3_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__el3_sp3_serror_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_synchronous_vector:
// Monitor (EL3) call.
// Check "smc #0x5ec3" was executed and no other reason code.
movz x1, #0x5ec3
movk x1, #0x5e00, lsl #16
mrs x2, ESR_EL3
cmp x1, x2
b.eq 1f
FASTSIM_DEBUG_HINT
b .
1: // Got here from an "smc". Branch to x0.
br x0
.text
.align 7
L__elx_64_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_64_serror_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_synchronous_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_irq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_fiq_vector:
FASTSIM_DEBUG_HINT
b .
.text
.align 7
L__elx_32_serror_vector:
FASTSIM_DEBUG_HINT
b .
/* Placeholder for macho_post_process.py. Placing the UUID here
allows debuggers to locate the UUID based on the value of VBAR */
.text
.align 7
_UUID:
.space 32
/* 64-bit first level exception handler dispatcher.
* Completes register context saving and branches to FLEH.
* Expects:
* {x0, x1, fp, lr, sp} - saved
* x0 - arm_context_t
* x1 - address of FLEH
* fp - previous stack frame if EL1
* lr - unused
* sp - kernel stack
*/
.text
.align 2
__dispatch64:
stp fp, lr, [sp, #-16]! // Create a frame to help debuggers unwind
mov fp, sp // past the exception handler
stp x2, x3, [x0, #16] // Save remaining GPRs
stp x4, x5, [x0, #32]
stp x6, x7, [x0, #48]
stp x8, x9, [x0, #64]
stp x10, x11, [x0, #80]
stp x12, x13, [x0, #96]
stp x14, x15, [x0, #112]
stp x16, x17, [x0, #128]
stp x18, x19, [x0, #144]
stp x20, x21, [x0, #160]
stp x22, x23, [x0, #176]
stp x24, x25, [x0, #192]
stp x26, x27, [x0, #208]
str x28, [x0, #224]
mrs lr, ELR_EL3 // Get exception link register
str lr, [x0, #264] // Save ELR to PCB
mrs x2, SPSR_EL3 // Get CPSR
str w2, [x0, #256] // Save CPSR to PCB
#if WITH_VFP
stp q0, q1, [x0, #304]
stp q2, q3, [x0, #336]
stp q4, q5, [x0, #368]
stp q6, q7, [x0, #400]
stp q8, q9, [x0, #432]
stp q10, q11, [x0, #464]
stp q12, q13, [x0, #496]
stp q14, q15, [x0, #528]
stp q16, q17, [x0, #560]
stp q18, q19, [x0, #592]
stp q20, q21, [x0, #624]
stp q22, q23, [x0, #656]
stp q24, q25, [x0, #688]
stp q26, q27, [x0, #720]
stp q28, q29, [x0, #752]
stp q30, q31, [x0, #784]
mrs x2, FPSR
str w2, [x0, #816]
mrs x2, FPCR
str w2, [x0, #820]
#endif
mov x21, x0 // Copy arm_context_t pointer to x21
blr x1
b __exception_return
.text
.align 2
__exception_return:
mov sp, x21 // Reload the arm_context_t pointer
#if WITH_VFP
ldp q0, q1, [sp, #304]
ldp q2, q3, [sp, #336]
ldp q4, q5, [sp, #368]
ldp q6, q7, [sp, #400]
ldp q8, q9, [sp, #432]
ldp q10, q11, [sp, #464]
ldp q12, q13, [sp, #496]
ldp q14, q15, [sp, #528]
ldp q16, q17, [sp, #560]
ldp q18, q19, [sp, #592]
ldp q20, q21, [sp, #624]
ldp q22, q23, [sp, #656]
ldp q24, q25, [sp, #688]
ldp q26, q27, [sp, #720]
ldp q28, q29, [sp, #752]
ldp q30, q31, [sp, #784]
ldr w3, [sp, #816]
msr FPSR, x3
ldr w4, [sp, #820]
msr FPCR, x4
#endif
ldr x0, [sp, #264] // Get the return address
msr ELR_EL3, x0 // Load the return address into ELR
ldr w1, [sp, #256] // Get the return CPSR
msr SPSR_EL3, x1 // Load the return CPSR into SPSR
ldp x0, x1, [sp, #0] // Restore the GPRs
ldp x2, x3, [sp, #16]
ldp x4, x5, [sp, #32]
ldp x6, x7, [sp, #48]
ldp x8, x9, [sp, #64]
ldp x10, x11, [sp, #80]
ldp x12, x13, [sp, #96]
ldp x14, x15, [sp, #112]
ldp x16, x17, [sp, #128]
ldp x18, x19, [sp, #144]
ldp x20, x21, [sp, #160]
ldp x22, x23, [sp, #176]
ldp x24, x25, [sp, #192]
ldp x26, x27, [sp, #208]
ldr x28, [sp, #224]
ldp fp, lr, [sp, #232]
/* Use exception stack to restore SP0 */
msr SPSel, #1 // Switch to SPx
stp x0, x1, [sp, #-16]! // Save x0 and x1
mrs x0, SP_EL0 // Reload the pcb pointer from SP0
ldr x1, [x0, #248] // Get the saved SP from the pcb
msr SP_EL0, x1 // Restore SP0
ldp x0, x1, [sp], #16 // Restore x0 and x1
eret
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2012-2013 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 <arch/arm/arm.h>
#include <debug.h>
#include <sys/task.h>
/*
* VFP/Neon support
*/
#if WITH_VFP
extern uint32_t arm_read_cpacr();
extern void arm_write_cpacr(uint32_t);
void arm_fp_init(void)
{
uint32_t cpacr;
/* v8: CPACR FPEN bits [21:20] needs to be programmed correctly to avoid a trap */
cpacr = arm_read_cpacr();
cpacr |= (3 << 20);
arm_write_cpacr(cpacr);
}
bool arch_task_fp_enable(bool enable)
{
return true;
}
#endif /* WITH_VFP */
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2011-2012 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 <debug.h>
#include <arch.h>
#include <arch/arch_task.h>
#include <arch/arm/arm.h>
#include <arch/arm64/proc_reg.h>
#include <sys.h>
#include <lib/libc.h>
#include <platform.h>
extern void platform_irq(void);
typedef enum {
ESR_EC_UNCATEGORIZED = 0x00,
ESR_EC_TRAP_SIMD_FP = 0x07,
ESR_EC_ILLEGAL_INSTR_SET = 0x0c,
ESR_EC_SVC_32 = 0x11,
ESR_EC_SVC_64 = 0x15,
ESR_EC_MSR_TRAP = 0x18,
ESR_EC_IABORT_EL0 = 0x20,
ESR_EC_IABORT_EL1 = 0x21,
ESR_EC_PC_ALIGN = 0x22,
ESR_EC_DABORT_EL0 = 0x24,
ESR_EC_DABORT_EL1 = 0x25,
ESR_EC_SP_ALIGN = 0x26
} esr_exception_class_t;
typedef enum {
FSC_TRANSLATION_FAULT_L0 = 0x04,
FSC_TRANSLATION_FAULT_L1 = 0x05,
FSC_TRANSLATION_FAULT_L2 = 0x06,
FSC_TRANSLATION_FAULT_L3 = 0x07,
FSC_ACCESS_FLAG_FAULT_L1 = 0x09,
FSC_ACCESS_FLAG_FAULT_L2 = 0x0A,
FSC_ACCESS_FLAG_FAULT_L3 = 0x0B,
FSC_PERMISSION_FAULT_L1 = 0x0D,
FSC_PERMISSION_FAULT_L2 = 0x0E,
FSC_PERMISSION_FAULT_L3 = 0x0F,
FSC_SYNC_EXT_ABORT = 0x10,
FSC_ASYNC_EXT_ABORT = 0x11,
FSC_SYNC_EXT_ABORT_TT_L1 = 0x15,
FSC_SYNC_EXT_ABORT_TT_L2 = 0x16,
FSC_SYNC_EXT_ABORT_TT_L3 = 0x17,
FSC_SYNC_PARITY = 0x18,
FSC_ASYNC_PARITY = 0x19,
FSC_SYNC_PARITY_TT_L1 = 0x1D,
FSC_SYNC_PARITY_TT_L2 = 0x1E,
FSC_SYNC_PARITY_TT_L3 = 0x1F,
FSC_ALIGNMENT_FAULT = 0x21,
FSC_DEBUG_FAULT = 0x22
} fault_status_t;
static const char *exception_codes[50] = {
[0x00] = "Unknown",
[0x0E] = "Illegal Instruction Set",
[0x21] = "Instruction Abort",
[0x22] = "PC Alignment",
[0x25] = "Data Abort",
[0x26] = "Stack Pointer Alignment",
[0x2F] = "SError",
};
void
arm_synchronous_exception(struct arm_exception_frame64 *frame)
{
const char **kind;
kind = &exception_codes[ESR_EC(frame->esr)];
panic("ARM synchronous abort at 0x%016llx:\n"
" esr 0x%08x (ec: %s, iss: 0x%08x) far 0x%016llx\n"
" x0 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x4 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x8 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x12 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x16 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x20 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x24 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x28 0x%016llx sp 0x%016llx lr 0x%016llx spsr 0x%08x\n",
frame->pc,
frame->esr, *kind, ESR_ISS(frame->esr), frame->far,
frame->regs[0], frame->regs[1], frame->regs[2], frame->regs[3],
frame->regs[4], frame->regs[5], frame->regs[6], frame->regs[7],
frame->regs[8], frame->regs[9], frame->regs[10], frame->regs[11],
frame->regs[12], frame->regs[13], frame->regs[14], frame->regs[15],
frame->regs[16], frame->regs[17], frame->regs[18], frame->regs[19],
frame->regs[20], frame->regs[21], frame->regs[22], frame->regs[23],
frame->regs[24], frame->regs[25], frame->regs[26], frame->regs[27],
frame->regs[28], frame->sp, frame->lr, frame->spsr);
}
void
arm_serror_exception(struct arm_exception_frame64 *frame)
{
const char **kind;
kind = &exception_codes[ESR_EC(frame->esr)];
platform_asynchronous_exception();
panic("ARM SError abort at 0x%016llx:\n"
" esr 0x%08x (ec: %s, iss: 0x%08x) far 0x%016llx\n"
" x0 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x4 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x8 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x12 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x16 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x20 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x24 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n"
" x28 0x%016llx sp 0x%016llx lr 0x%016llx spsr 0x%08x\n",
frame->pc,
frame->esr, *kind, ESR_ISS(frame->esr), frame->far,
frame->regs[0], frame->regs[1], frame->regs[2], frame->regs[3],
frame->regs[4], frame->regs[5], frame->regs[6], frame->regs[7],
frame->regs[8], frame->regs[9], frame->regs[10], frame->regs[11],
frame->regs[12], frame->regs[13], frame->regs[14], frame->regs[15],
frame->regs[16], frame->regs[17], frame->regs[18], frame->regs[19],
frame->regs[20], frame->regs[21], frame->regs[22], frame->regs[23],
frame->regs[24], frame->regs[25], frame->regs[26], frame->regs[27],
frame->regs[28], frame->sp, frame->lr, frame->spsr);
}
void
arm_irq()
{
_irq_enter_critical_section();
platform_irq();
_irq_exit_critical_section();
}
+599
View File
@@ -0,0 +1,599 @@
/*
* Copyright (c) 2007-2011, 2014 Apple Inc. All rights reserved.
*/
/*
* Processor registers for ARM64
*/
#ifndef _ARM64_PROC_REG_H_
#define _ARM64_PROC_REG_H_
// Pick the right registers depending on the exception level we're booting into.
#if WITH_EL3
#define SCTLR_ELx SCTLR_EL3
#define MAIR_ELx MAIR_EL3
#define TCR_ELx TCR_EL3
#define TTBR0_ELx TTBR0_EL3
#define VBAR_ELx VBAR_EL3
#else
#define SCTLR_ELx SCTLR_EL1
#define MAIR_ELx MAIR_EL1
#define TCR_ELx TCR_EL1
#define TTBR0_ELx TTBR0_EL1
#define VBAR_ELx VBAR_EL1
#endif
/*
* 64-bit Program Status Register (PSR64)
*
* 31 27 22 21 20 19 10 9 5 4 0
* +-+-+-+-+------+--+--+----------+-+-+-+-+-+-----+
* |N|Z|C|V|000000|SS|IL|0000000000|D|A|I|F|0| M |
* +-+-+-+-+-+----+--+--+----------+-+-+-+-+-+-----+
*
* where:
* NZCV Comparison flags
* SS Single step
* IL Illegal state
* DAIF Interrupt masks
* M Mode field
*/
#define PSR64_NZCV_SHIFT 28
#define PSR64_NZCV_MASK (1 << PSR64_NZCV_SHIFT)
#define PSR64_N_SHIFT 31
#define PSR64_N (1 << PSR64_N_SHIFT)
#define PSR64_Z_SHIFT 30
#define PSR64_Z (1 << PSR64_Z_SHIFT)
#define PSR64_C_SHIFT 29
#define PSR64_C (1 << PSR64_C_SHIFT)
#define PSR64_V_SHIFT 28
#define PSR64_V (1 << PSR64_V_SHIFT)
#define PSR64_SS_SHIFT 21
#define PSR64_SS (1 << PSR64_SS_SHIFT)
#define PSR64_IL_SHIFT 20
#define PSR64_IL (1 << PSR64_IL_SHIFT)
/*
* msr DAIF, Xn and mrs Xn, DAIF transfer into
* and out of bits 9:6
*/
#define DAIF_DEBUG_SHIFT 9
#define DAIF_DEBUGF (1 << DAIF_DEBUG_SHIFT)
#define DAIF_ASYNC_SHIFT 8
#define DAIF_ASYNCF (1 << DAIF_ASYNC_SHIFT)
#define DAIF_IRQF_SHIFT 7
#define DAIF_IRQF (1 << DAIF_IRQF_SHIFT)
#define DAIF_FIQF_SHIFT 6
#define DAIF_FIQF (1 << DAIF_FIQF_SHIFT)
#define DAIF_ALL (DAIF_DEBUGF | DAIF_ASYNCF | DAIF_IRQF | DAIF_FIQF)
#define DAIF_STANDARD_DISABLE (DAIF_ASYNCF | DAIF_IRQF | DAIF_FIQF)
#define SPSR_INTERRUPTS_ENABLED(x) (!(x & DAIF_FIQF))
/*
* msr DAIFSet, Xn, and msr DAIFClr, Xn transfer
* from bits 3:0.
*/
#define DAIFSC_DEBUGF (1 << 3)
#define DAIFSC_ASYNCF (1 << 2)
#define DAIFSC_IRQF (1 << 1)
#define DAIFSC_FIQF (1 << 0)
#define DAIFSC_ALL (DAIFSC_DEBUGF | DAIFSC_ASYNCF | DAIFSC_IRQF | DAIFSC_FIQF)
#define DAIFSC_STANDARD_DISABLE (DAIFSC_ASYNCF | DAIFSC_IRQF | DAIFSC_FIQF)
/*
* ARM64_TODO: unify with ARM?
*/
#define PSR64_CF 0x20000000 /* Carry/Borrow/Extend */
#define PSR64_MODE_MASK 0x1F
#define PSR64_MODE_USER32_THUMB 0x20
#define PSR64_MODE_RW_SHIFT 4
#define PSR64_MODE_RW_64 0
#define PSR64_MODE_RW_32 (0x1 << PSR64_MODE_RW_SHIFT)
#define PSR64_MODE_EL_SHIFT 2
#define PSR64_MODE_EL_MASK (0x3 << PSR64_MODE_EL_SHIFT)
#define PSR64_MODE_EL3 (0x3 << PSR64_MODE_EL_SHIFT)
#define PSR64_MODE_EL1 (0x1 << PSR64_MODE_EL_SHIFT)
#define PSR64_MODE_EL0 0
#define PSR64_MODE_SPX 0x1
#define PSR64_MODE_SP0 0
#define PSR64_USER32_DEFAULT (PSR64_MODE_RW_32 | PSR64_MODE_EL0 | PSR64_MODE_SP0)
#define PSR64_USER64_DEFAULT (PSR64_MODE_RW_64 | PSR64_MODE_EL0 | PSR64_MODE_SP0)
#define PSR64_KERNEL_DEFAULT (DAIF_STANDARD_DISABLE | PSR64_MODE_RW_64 | PSR64_MODE_EL1 | PSR64_MODE_SP0)
#define PSR64_IS_KERNEL(x) ((x & PSR64_MODE_EL_MASK) == PSR64_MODE_EL1)
#define PSR64_IS_USER(x) ((x & PSR64_MODE_EL_MASK) == PSR64_MODE_EL0)
/*
* Floating Point Control Register (FPCR)
*/
#define FPCR_DN (1 << 25)
#define FPCR_DEFAULT (FPCR_DN)
/*
* System Control Register (SCTLR)
*
* 31 26 25 24 23 19 18 15 14 13 12 11 7 6 5 4 3 2 1 0
* +-----+---+--+---+----+---+---+---+---+--+--+----+---+----+------+---+--+-+-+-+
* |00110|UCI|EE|E0E|1101|WXN|101|UCT|DZE| 0|I |1000|ITD|THEE|C15BEN|SA0|SA|D|A|M|
* +-----+---+--+---+----+---+---+---+---+--+--+----+---+----+------+---+--+-+-+-+
*
* UCI User Cache Instructions
* EE Exception Endianness
* E0E EL0 Endianness
* WXN Writeable implies eXecute Never
* UCT User Cache Type register (CTR_EL0)
* DZE user Data Cache Zero (DC ZVA)
* I Instruction cache enable
* ITD IT Disable
* THEE THumb EE enable
* CP15BEN CP15 Barrier ENable
* SA0 Stack Alignment check for EL0
* SA Stack Alignment check enable
* D Data/unified cache enable
* A Alignment check enable
* M MMU enable
*/
#define SCTLR_RESERVED 0x30d50800
#define SCTLR_UCI_ENABLED (1 << 26)
#define SCTLR_EE_ENABLED (1 << 25)
#define SCTLR_E0E_ENABLED (1 << 24)
#define SCTLR_WXN_ENABLED (1 << 19)
#define SCTLR_UCT_ENABLED (1 << 15)
#define SCTLR_DZE_ENABLED (1 << 14)
#define SCTLR_I_ENABLED (1 << 12)
#define SCTLR_ITD_DISABLED (1 << 7)
#define SCTLR_THEE_ENABLED (1 << 6)
#define SCTLR_CP15BEN_ENABLED (1 << 5)
#define SCTLR_SA0_ENABLED (1 << 4)
#define SCTLR_SA_ENABLED (1 << 3)
#define SCTLR_D_ENABLED (1 << 2)
#define SCTLR_A_ENABLED (1 << 1)
#define SCTLR_M_ENABLED (1 << 0)
#define SCTLR_EL1_DEFAULT (SCTLR_RESERVED | SCTLR_I_ENABLED | SCTLR_SA_ENABLED | SCTLR_D_ENABLED | SCTLR_M_ENABLED)
/*
* Secure Configuratio Register (SCR)
*
* 31 12 0
* +---+---+------+------+--------------------+
* |00000000000000000000 ||
* +---+---+------+------+--------------------+
*
* where:
* TTA Trace trap
* FPEN Floating point enable
*/
#define SCR_EA_SHIFT (3)
#define SCR_EA (1 << SCR_EA_SHIFT)
#define SCR_FIQ_SHIFT (2)
#define SCR_FIQ (1 << SCR_FIQ_SHIFT)
#define SCR_IRQ_SHIFT (1)
#define SCR_IRQ (1 << SCR_IRQ_SHIFT)
#define SCR_DEFAULT (SCR_EA | SCR_FIQ | SCR_IRQ)
/*
* Coprocessor Access Control Register (CPACR)
*
* 31 28 27 22 21 20 19 0
* +---+---+------+------+--------------------+
* |000|TTA|000000| FPEN |00000000000000000000|
* +---+---+------+------+--------------------+
*
* where:
* TTA Trace trap
* FPEN Floating point enable
*/
#define CPACR_TTA_SHIFT 28
#define CPACR_TTA (1 << CPACR_TTA_SHIFT)
#define CPACR_FPEN_SHIFT 20
#define CPACR_FPEN_EL0_TRAP (0x1 << CPACR_FPEN_SHIFT)
#define CPACR_FPEN_ENABLE (0x3 << CPACR_FPEN_SHIFT)
/*
* Translation Control Register (TCR) - EL3
*
* 31 30 24 23 22 21 20 19 18 16 14 13 12 11 10 9 8 7 6 5 0
* +-+-------+--+-----+---+--+-----+---+-----+-----+-----+-+-+----+
* |1| 0 | 1| 0 |TBI| 0| PS |TG0| SH0 |ORGN0|IRGN0|0|0|T0SZ|
* +-+-------+--+-----+---+--+-----+---+-----+-----+-----+-+-+----+
*
* TBI Top Byte Ignored for TTBR0 region
* PS Physical Address Size limit
* TG0 Granule Size for TTBR0 region
* SH0 Shareability for TTBR0 region
* ORGN0 Outer Cacheability for TTBR0 region
* IRGN0 Inner Cacheability for TTBR0 region
* T0SZ Virtual address size for TTBR0
* Translation Control Register (TCR) - EL1
*
* 63 39 38 37 36 34 32 30 29 28 27 26 25 24 23 22 21 16 14 13 12 11 10 9 8 7 5 0
* +------+----+----+--+-+-----+-+---+-----+-----+-----+----+--+------+-+---+-----+-----+-----+----+-+----+
* | 0 |TBI1|TBI0|AS|0| IPS |0|TG1| SH1 |ORGN1|IRGN1|EPD1|A1| T1SZ |0|TG0| SH0 |ORGN0|IRGN0|EPD0|0|T0SZ|
* +------+----+----+--+-+-----+-+---+-----+-----+-----+----+--+------+-+---+-----+-----+-----+----+-+----+
*
* TBI1 Top Byte Ignored for TTBR1 region
* TBI0 Top Byte Ignored for TTBR0 region
* AS ASID Size
* IPS Physical Address Size limit
* TG1 Granule Size for TTBR1 region
* SH1 Shareability for TTBR1 region
* ORGN1 Outer Cacheability for TTBR1 region
* IRGN1 Inner Cacheability for TTBR1 region
* EPD1 Translation table walk disable for TTBR1
* A1 ASID selection from TTBR1 enable
* T1SZ Virtual address size for TTBR1
* TG0 Granule Size for TTBR0 region
* SH0 Shareability for TTBR0 region
* ORGN0 Outer Cacheability for TTBR0 region
* IRGN0 Inner Cacheability for TTBR0 region
* T0SZ Virtual address size for TTBR0
*/
// Common defintions for EL1 and EL3 versions of this register
#define TCR_ELx_T0SZ_SHIFT 0
#define TCR_ELx_IRGN0_SHIFT 8
#define TCR_ELx_IRGN0_DISABLED (0ULL << TCR_ELx_IRGN0_SHIFT)
#define TCR_ELx_IRGN0_WRITEBACK (1ULL << TCR_ELx_IRGN0_SHIFT)
#define TCR_ELx_IRGN0_WRITETHRU (2ULL << TCR_ELx_IRGN0_SHIFT)
#define TCR_ELx_IRGN0_WRITEBACKNO (3ULL << TCR_ELx_IRGN0_SHIFT)
#define TCR_ELx_ORGN0_SHIFT 10
#define TCR_ELx_ORGN0_DISABLED (0ULL << TCR_ELx_ORGN0_SHIFT)
#define TCR_ELx_ORGN0_WRITEBACK (1ULL << TCR_ELx_ORGN0_SHIFT)
#define TCR_ELx_ORGN0_WRITETHRU (2ULL << TCR_ELx_ORGN0_SHIFT)
#define TCR_ELx_ORGN0_WRITEBACKNO (3ULL << TCR_ELx_ORGN0_SHIFT)
#define TCR_ELx_SH0_SHIFT 12
#define TCR_ELx_SH0_NONE (0ULL << TCR_ELx_SH0_SHIFT)
#define TCR_ELx_SH0_OUTER (2ULL << TCR_ELx_SH0_SHIFT)
#define TCR_ELx_SH0_INNER (3ULL << TCR_ELx_SH0_SHIFT)
#define TCR_ELx_TG0_GRANULE_SHIFT 14
#define TCR_ELx_TG0_GRANULE_4KB (0ULL << TCR_ELx_TG0_GRANULE_SHIFT)
#define TCR_ELx_TG0_GRANULE_64KB (1ULL << TCR_ELx_TG0_GRANULE_SHIFT)
#define TCR_ELx_TG0_GRANULE_16KB (2ULL << TCR_ELx_TG0_GRANULE_SHIFT)
#if WITH_EL3
// EL3-specific TCR register definitions
#define TCR_EL3_PS_SHIFT 16
#define TCR_EL3_PS_32BITS (0ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_PS_36BITS (1ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_PS_40BITS (2ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_PS_42BITS (3ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_PS_44BITS (4ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_PS_48BITS (5ULL << TCR_EL3_PS_SHIFT)
#define TCR_EL3_TBI_TOPBYTE_IGNORED (1ULL << 20)
#else
// EL1-specific TCR register definitions
#define TCR_EL1_EPD0_TTBR0_DISABLED (1ULL << 7)
#define TCR_EL1_T1SZ_SHIFT 16
#define TCR_EL1_A1_ASID1 (1ULL << 22)
#define TCR_EL1_EPD1_TTBR1_DISABLED (1ULL << 23)
#define TCR_EL1_IRGN1_SHIFT 24
#define TCR_EL1_IRGN1_DISABLED (0ULL << TCR_EL1_IRGN1_SHIFT)
#define TCR_EL1_IRGN1_WRITEBACK (1ULL << TCR_EL1_IRGN1_SHIFT)
#define TCR_EL1_IRGN1_WRITETHRU (2ULL << TCR_EL1_IRGN1_SHIFT)
#define TCR_EL1_IRGN1_WRITEBACKNO (3ULL << TCR_EL1_IRGN1_SHIFT)
#define TCR_EL1_ORGN1_SHIFT 26
#define TCR_EL1_ORGN1_DISABLED (0ULL << TCR_EL1_ORGN1_SHIFT)
#define TCR_EL1_ORGN1_WRITEBACK (1ULL << TCR_EL1_ORGN1_SHIFT)
#define TCR_EL1_ORGN1_WRITETHRU (2ULL << TCR_EL1_ORGN1_SHIFT)
#define TCR_EL1_ORGN1_WRITEBACKNO (3ULL << TCR_EL1_ORGN1_SHIFT)
#define TCR_EL1_SH1_SHIFT 28
#define TCR_EL1_SH1_NONE (0ULL << TCR_EL1_SH1_SHIFT)
#define TCR_EL1_SH1_OUTER (2ULL << TCR_EL1_SH1_SHIFT)
#define TCR_EL1_SH1_INNER (3ULL << TCR_EL1_SH1_SHIFT)
#define TCR_EL1_TG1_GRANULE_SHIFT 30
#define TCR_EL1_TG1_GRANULE_16KB (1ULL << TCR_EL1_TG1_GRANULE_SHIFT)
#define TCR_EL1_TG1_GRANULE_4KB (2ULL << TCR_EL1_TG1_GRANULE_SHIFT)
#define TCR_EL1_TG1_GRANULE_64KB (3ULL << TCR_EL1_TG1_GRANULE_SHIFT)
#define TCR_EL1_IPS_SHIFT 32
#define TCR_EL1_IPS_32BITS (0ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_IPS_36BITS (1ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_IPS_40BITS (2ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_IPS_42BITS (3ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_IPS_44BITS (4ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_IPS_48BITS (5ULL << TCR_EL1_IPS_SHIFT)
#define TCR_EL1_AS_16BIT_ASID (1ULL << 36)
#define TCR_EL1_TBI0_TOPBYTE_IGNORED (1ULL << 37)
#define TCR_EL1_TBI1_TOPBYTE_IGNORED (1ULL << 38)
#endif
/*
* Translation Table Base Register (TTBR)
*
* 63 48 47 x x-1 0
* +--------+------------------+------+
* | ASID | Base Address | zero |
* +--------+------------------+------+
*
*/
#define TTBR_ASID_SHIFT 48
#define TTBR_ASID_MASK 0xffff000000000000
#define TTBR_BADDR_MASK 0x0000ffffffffffff
/*
* Memory Attribute Indirection Register
*
* 63 56 55 48 47 40 39 32 31 24 23 16 15 8 7 0
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Attr7 | Attr6 | Attr5 | Attr4 | Attr3 | Attr2 | Attr1 | Attr0 |
* +-------+-------+-------+-------+-------+-------+-------+-------+
*
*/
#define MAIR_ATTR_SHIFT(x) (8*(x))
/* Strongly ordered or device memory attributes */
#define MAIR_OUTER_STRONGLY_ORDERED 0x0
#define MAIR_OUTER_DEVICE 0x0
#define MAIR_INNER_STRONGLY_ORDERED 0x0
#define MAIR_INNER_DEVICE 0x4
/* Normal memory attributes */
#define MAIR_OUTER_NON_CACHEABLE 0x40
#define MAIR_OUTER_WRITE_THROUGH 0x80
#define MAIR_OUTER_WRITE_BACK 0xc0
#define MAIR_INNER_NON_CACHEABLE 0x4
#define MAIR_INNER_WRITE_THROUGH 0x8
#define MAIR_INNER_WRITE_BACK 0xc
/* Allocate policy for cacheable memory */
#define MAIR_OUTER_WRITE_ALLOCATE 0x10
#define MAIR_OUTER_READ_ALLOCATE 0x20
#define MAIR_INNER_WRITE_ALLOCATE 0x1
#define MAIR_INNER_READ_ALLOCATE 0x2
/* Memory Atribute Encoding */
#define MAIR_DISABLE 0x04 /* Strongly Ordered */
#define MAIR_WRITECOMB 0x44 /* Normal Memory, Outer Non-Cacheable, Inner Non-Cacheable */
#define MAIR_WRITETHRU 0xBB /* Normal Memory, Outer Write-through, Inner Write-through */
#define MAIR_WRITEBACK 0xFF /* Normal Memory, Outer Write-back, Inner Write-back */
#define MAIR_INNERWRITEBACK 0x4F /* Normal Memory, Outer Non-Cacheable, Inner Write-back */
/*
* ARM 4-level Page Table support - 2*1024TB (2^48) of address space
*/
/*
* Memory Attribute Index
*/
#define CACHE_ATTRINDX_DISABLE 0x0 /* no cache, no buffer */
#define CACHE_ATTRINDX_WRITEBACK 0x1 /* cache enabled, buffer enabled */
#define CACHE_ATTRINDX_WRITECOMB 0x1 /* no cache, buffered writes */
#define CACHE_ATTRINDX_WRITETHRU 0x2 /* cache enabled, buffer disabled */
#define CACHE_ATTRINDX_INNERWRITEBACK 0x4 /* inner cache enabled, buffer enabled, write allocate */
#define CACHE_ATTRINDX_DEFAULT CACHE_ATTRINDX_WRITEBACK
/*
* Access protection bit values (TTEs and PTEs)
*/
#define AP_RWNA 0x0 /* priv=read-write, user=no-access */
#define AP_RWRW 0x1 /* priv=read-write, user=read-write */
#define AP_RONA 0x2 /* priv=read-only, user=no-access */
#define AP_RORO 0x3 /* priv=read-only, user=read-only */
#define AP_MASK 0x3 /* mask to find ap bits */
/*
* Shareability attributes
*/
#define SH_NONE 0x0 /* Non shareable */
#define SH_OUTER_MEMORY 0x2 /* Normal memory Inner shareable - Outer shareable */
#define SH_INNER_MEMORY 0x3 /* Normal memory Inner shareable - Outer non shareable */
/*
* LPAE/ARMv8 Table Entry
*
* 63 62 61 60 59 58 52 51 48 47 12 11 2 1 0
* ,--+-----+--+---+-------+------+----------------------+-------+-+-.
* |NS| AP |XN|PXN|ignored| zero | TableOutputAddress |ignored|1|V|
* `--+-----+--+---+-------+------+----------------------+-------+-+-'
*
* LPAE/ARMv8 Block Entry
*
* 63 59 58 55 54 53 52 51 48 47 12 11 10 9 8 7 6 5 4 2 1 0
* ,-----+-----+--+---+----+-----+-------------+--+--+----+----+--+-------+-+-.
* | ign | SW |XN|PXN|HINT| zero|OutputAddress|nG|AF| SH | AP |NS|AttrIdx|W|V|
* `-----+-----+--+---+----+-----+-------------+--+--+----+----+--+-------+-+-'
*
* NS (NSTable) Non-Secure: NS=1 for everything outside of TZ region
* AP (APTable) Access Permission: AP[2:1]=0 for RW, 2 for RO
* XN (XNTable) eXecute Never: XN=0 for code, 1 for data
* PXN (PXNTable) Privileged eXecute Never: 1=dont execute when EL3
* TableOutputAddress Next physical base: Lower bits 0 as alignment requires.
* SW Reserved for software use (unused, can have metadata)
* HINT Contiguous hint. Optimization only, leave as 0.
* OutputAddress Block physical base: Lower bits 0 as alignment requires.
* nG notGlobal: nG=1 restricts TLB hit to matching ASID
* AF Access Flag: 0=never,1=hit. ARMv8 may fault if 0.
* SH Shareability, SH[1:0]=2 for normal memory
* AttrIdx Memory Attribute Index, 0 for device, 1 for normal
* W "Walk" flag: L0-2 0=Block,1=Table; L3 0=Fault,1=Block
*/
#define ARM_LPAE_TABLE_MASK (0x0000fffffffff000ULL) /* mask for extracting pointer to next table (works at any level) */
#define ARM_LPAE_NSTABLE 0x8000000000000000ULL /* value for a secure mapping */
#define ARM_LPAE_NSTABLE_MASK 0x8000000000000000ULL /* notSecure mapping mask */
#define ARM_LPAE_APTABLE_SHIFT 61
#define ARM_LPAE_APTABLE(x) ((x)<<ARM_LPAE_APTABLE_SHIFT) /* access protection */
#define ARM_LPAE_XNTABLE 0x1000000000000000ULL /* value for no execute */
#define ARM_LPAE_XNTABLE_MASK 0x1000000000000000ULL /* no execute mask */
#define ARM_LPAE_PXNTABLE 0x0800000000000000ULL /* value for privilege no execute bit */
#define ARM_LPAE_PXNTABLE_MASK 0x0800000000000000ULL /* privilege execute mask */
#define ARM_LPAE_XN 0x0040000000000000ULL /* value for no execute */
#define ARM_LPAE_XN_MASK 0x0040000000000000ULL /* no execute mask */
#define ARM_LPAE_PXN 0x0020000000000000ULL /* value for privilege no execute bit */
#define ARM_LPAE_PXN_MASK 0x0020000000000000ULL /* privilege execute mask */
#define ARM_LPAE_NG 0x0000000000000800ULL /* value for a global mapping */
#define ARM_LPAE_NG_MASK 0x0000000000000800ULL /* notGlobal mapping mask */
#define ARM_LPAE_AF 0x0000000000000400ULL /* value for access */
#define ARM_LPAE_AF_MASK 0x0000000000000400ULL /* access mask */
#define ARM_LPAE_SH_SHIFT 8
#define ARM_LPAE_SH(x) ((x) << ARM_LPAE_SH_SHIFT) /* access shared */
#define ARM_LPAE_SH_MASK (0x3ULL << ARM_LPAE_SH_SHIFT) /* mask access shared */
#define ARM_LPAE_AP_SHIFT 6
#define ARM_LPAE_AP(x) ((x)<<ARM_LPAE_AP_SHIFT) /* access protection */
#define ARM_LPAE_AP_MASK (0x3ULL<<ARM_LPAE_AP_SHIFT)
#define ARM_LPAE_NS 0x0000000000000020ULL /* value for a secure mapping */
#define ARM_LPAE_MASK 0x0000000000000020ULL /* notSecure mapping mask */
#define ARM_LPAE_ATTRINDX_SHIFT 2 /* memory attributes index */
#define ARM_LPAE_ATTRINDX(x) ((x) << ARM_LPAE_ATTRINDX_SHIFT) /* memory attributes index */
#define ARM_LPAE_ATTRINDX_MASK (0x3ULL << ARM_LPAE_ATTRINDX_SHIFT) /* mask memory attributes index */
#define ARM_LPAE_TYPE_MASK 0x0000000000000002ULL /* mask for extracting the type */
#define ARM_LPAE_TYPE_TABLE 0x0000000000000002ULL /* page table type */
#define ARM_LPAE_TYPE_L0L1L2BLOCK 0x0000000000000000ULL /* block entry type */
#define ARM_LPAE_TYPE_L3BLOCK 0x0000000000000002ULL /* L3 is different */
#define ARM_LPAE_VALID 0x0000000000000001ULL /* valid entry */
/*
* Exception Syndrome Register
*
* 31 26 25 24 0
* +------+--+------------------+
* | EC |IL| ISS |
* +------+--+------------------+
*
* EC - Exception Class
* IL - Instruction Length
* ISS- Instruction Specific Syndrome
*
* Note: The ISS can have many forms. These are defined separately below.
*/
#define ESR_EC_SHIFT 26
#define ESR_EC_MASK (0x3F << ESR_EC_SHIFT)
#define ESR_EC(x) ((x & ESR_EC_MASK) >> ESR_EC_SHIFT)
#define ESR_IL_SHIFT 25
#define ESR_IL (1 < ESR_IL_SHIFT)
#define ESR_IS_THUMB(x) (!(x & ESR_IL))
#define ESR_ISS_MASK 0x01FFFFFF
#define ESR_ISS(x) (x & ESR_ISS_MASK)
/*
* Instruction Abort ISS (EL1)
* 24 10 9 5 0
* +---------------+--+---+------+
* |000000000000000|EA|000| IFSC |
* +---------------+--+---+------+
*
* where:
* EA External Abort type
* IFSC Instruction Fault Status Code
*/
#define ISS_IA_EA_SHIFT 9
#define ISS_IA_EA (0x1 << ISS_IA_EA_SHIFT)
#define ISS_IA_FSC_MASK 0x2F
#define ISS_IA_FSC(x) (x & ISS_DA_FSC_MASK)
/*
* Data Abort ISS (EL1)
*
* 24 9 8 7 6 5 0
* +---------------+--+--+-+---+----+
* |000000000000000|EA|CM|0|WnR|DFSC|
* +---------------+--+--+-+---+----+
*
* where:
* EA External Abort type
* CM Cache Maintenance operation
* WnR Write not Read
* DFSC Data Fault Status Code
*/
#define ISS_DA_EA_SHIFT 9
#define ISS_DA_EA (0x1 << ISS_DA_EA_SHIFT)
#define ISS_DA_CM_SHIFT 8
#define ISS_DA_CM (0x1 << ISS_DA_CM_SHIFT)
#define ISS_DA_WNR_SHIFT 6
#define ISS_DA_WNR (0x1 << ISS_DA_WNR_SHIFT)
#define ISS_DA_FSC_MASK 0x2F
#define ISS_DA_FSC(x) (x & ISS_DA_FSC_MASK)
#define PLATFORM_SYSCALL_TRAP_NO 0x80000000
#define ARM64_SYSCALL_CODE_REG_NUM (16)
#define ARM64_CLINE_SHIFT 6
/*
* Timer definitions.
*/
#define CNTKCTL_EL1_PL0PTEN (0x1 << 9) /* 1: EL0 access to physical timer regs permitted */
#define CNTKCTL_EL1_PL0VTEN (0x1 << 8) /* 1: EL0 access to virtual timer regs permitted */
#define CNTKCTL_EL1_EVENTI_MASK (0x000000f0) /* Mask for bits describing which bit to use for triggering event stream */
#define CNTKCTL_EL1_EVENTI_SHIFT (0x4) /* Shift for same */
#define CNTKCTL_EL1_EVENTDIR (0x1 << 3) /* 1: one-to-zero transition of specified bit causes event */
#define CNTKCTL_EL1_EVNTEN (0x1 << 2) /* 1: enable event stream */
#define CNTKCTL_EL1_PL0VCTEN (0x1 << 1) /* 1: EL0 access to physical timebase + frequency reg enabled */
#define CNTKCTL_EL1_PL0PCTEN (0x1 << 0) /* 1: EL0 access to virtual timebase + frequency reg enabled */
#endif /* _ARM64_PROC_REG_H_ */
+1
View File
@@ -0,0 +1 @@
_start
+543
View File
@@ -0,0 +1,543 @@
/*
* Copyright (C) 2012-2014 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.
*/
/*
* See docs/mmu64.txt for an in-depth version of what is going on here.
* Short version:
* - H6, H7 use 4KB page granule.
* - H8 uses 16KB page granule (4KB not supported by hardware).
* - Start at L1 for 4KB page granule.
* - Start at L2 for 16KB page granule.
* - Set virtual memory limit so the first level (L0/L1) has just two entries.
* - ...then never touch the top level so we don't suffer from NS/S coherency.
*/
#include <debug.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arch/arm/arm.h>
#include <arch/arm64/proc_reg.h>
#ifndef TEST
# include <sys.h>
# include <arch.h>
# include <platform.h>
# include <platform/memmap.h>
#endif
#define LAST_TABLE_LEVEL 3
extern uint64_t arm_read_sctlr();
// Start level page table entries
static uint64_t *tt_top_level;
// Allocation area and current allocation pointer.
static addr_t tt_alloc_start, tt_alloc_next, tt_alloc_end;
#ifdef TEST
// Mock test interfaces for mmu.c, implemented in mmu_test.c
void mmu_printf(int verbosity, const char *fmt, ...);
unsigned get_page_granule_shift(void);
void mmu_get_memmap(addr_t *page_tables_base,
size_t *page_tables_size);
void platform_mmu_setup(bool resume);
void get_table_entry_hook(unsigned level, addr_t table_base, size_t index);
void set_table_entry_hook(unsigned level, addr_t table_base, size_t index,
uint64_t value);
#else // !defined(TEST)
// Real interfaces, designed to be inlined. These have no host-side coverage,
// so they should be no-ops or simple constants.
// No printf spew.
static void mmu_printf(int verbosity, const char *fmt, ...)
{
(void) verbosity;
(void) fmt;
}
// Constants.
static unsigned get_page_granule_shift(void) { return PAGE_GRANULE_SHIFT; }
static void mmu_get_memmap(addr_t *page_tables_base,
size_t *page_tables_size)
{
*page_tables_base = PAGE_TABLES_BASE;
*page_tables_size = PAGE_TABLES_SIZE;
}
// Remove expensive validity checking.
static void get_table_entry_hook(unsigned level, addr_t table_base,
size_t index)
{
(void) level; (void) table_base; (void) index;
}
static void set_table_entry_hook(unsigned level, addr_t table_base,
size_t index, uint64_t value)
{
(void) level; (void) table_base; (void) index; (void) value;
}
#endif // !defined(TEST)
#define mmu_spew(x...) mmu_printf(1, x)
#define mmu_extra_spew(x...) mmu_printf(2, x)
static void assert_valid_level(unsigned level)
{
ASSERT((get_page_granule_shift() == 12 || level >= 1) &&
level <= LAST_TABLE_LEVEL);
}
static bool level_permits_blocks(unsigned level)
{
assert_valid_level(level);
// No granule supports L0 blocks.
// 4KB granule supports L1 blocks.
// All granules support L2 and L3 blocks.
return (level == 1 && get_page_granule_shift() == 12) || level >= 2;
}
static uint64_t get_table_entry(unsigned level, addr_t table_base,
size_t index)
{
get_table_entry_hook(level, table_base, index);
mmu_extra_spew("get_table_entry(%u, 0x%llx, %u) ",
level, (unsigned long long) table_base,
(unsigned) index);
// No possible aliases, known aligned.
uint64_t result = *(uint64_t *) (table_base + index * 8);
mmu_extra_spew("= 0x%016llx\n", (unsigned long long) result);
return result;
}
static void set_table_entry(unsigned level, addr_t table_base, size_t index,
uint64_t value)
{
set_table_entry_hook(level, table_base, index, value);
mmu_extra_spew("set_table_entry(%u, 0x%llx, %u, 0x%llx)\n",
level, (unsigned long long) table_base, (unsigned) index,
(unsigned long long) value);
*((volatile uint64_t *) (table_base + index * 8)) = value;
}
static unsigned get_start_level(void)
{
switch (get_page_granule_shift()) {
case 12: return 1;
case 14: return 2;
case 16: return 2;
default: panic("Bad granule");
}
}
static unsigned get_virt_address_bits(void)
{
switch (get_page_granule_shift()) {
case 12: return 36;
case 14: return 36;
case 16: return 36;
default: panic("Bad granule");
}
}
static uint64_t get_mair(void)
{
return (MAIR_WRITEBACK << MAIR_ATTR_SHIFT(CACHE_ATTRINDX_WRITEBACK)) |
(MAIR_DISABLE << MAIR_ATTR_SHIFT(CACHE_ATTRINDX_DISABLE));
}
static uint64_t get_tcr(void)
{
// Form the contents of the TCR register for the selected
// virtual address limit and page granule.
uint64_t tcr;
uint32_t txsz = 64 - get_virt_address_bits();
#if WITH_EL3
switch (get_page_granule_shift()) {
case 12: tcr = TCR_ELx_TG0_GRANULE_4KB; break;
case 14: tcr = TCR_ELx_TG0_GRANULE_16KB; break;
case 16: tcr = TCR_ELx_TG0_GRANULE_64KB; break;
default: panic("Bad granule");
}
tcr |= TCR_EL3_PS_36BITS |
TCR_ELx_SH0_OUTER | TCR_ELx_ORGN0_WRITEBACK | TCR_ELx_IRGN0_WRITEBACK |
(txsz << TCR_ELx_T0SZ_SHIFT);
#else
switch (get_page_granule_shift()) {
case 12: tcr = TCR_ELx_TG0_GRANULE_4KB | TCR_EL1_TG1_GRANULE_4KB; break;
case 14: tcr = TCR_ELx_TG0_GRANULE_16KB | TCR_EL1_TG1_GRANULE_16KB; break;
case 16: tcr = TCR_ELx_TG0_GRANULE_64KB | TCR_EL1_TG1_GRANULE_64KB; break;
default: panic("Bad granule");
}
tcr |= TCR_EL1_IPS_36BITS |
TCR_ELx_SH0_OUTER | TCR_ELx_ORGN0_WRITEBACK | TCR_ELx_IRGN0_WRITEBACK |
(txsz << TCR_ELx_T0SZ_SHIFT) |
TCR_EL1_EPD1_TTBR1_DISABLED |
TCR_EL1_SH1_OUTER | TCR_EL1_ORGN1_WRITEBACK | TCR_EL1_IRGN1_WRITEBACK |
(txsz << TCR_EL1_T1SZ_SHIFT);
#endif
return tcr;
}
static uint64_t get_table_flags(void)
{
// All table walks after the start level are non-secure.
return ARM_LPAE_NSTABLE | ARM_LPAE_TYPE_TABLE | ARM_LPAE_VALID;
}
static uint64_t get_block_flags(unsigned level, arm_mmu_extended_attr_t attr)
{
assert_valid_level(level);
RELEASE_ASSERT(level_permits_blocks(level));
bool normal, writable, executable;
switch (attr) {
case kARMMMUDeviceR:
normal = false; writable = false; executable = false; break;
case kARMMMUDeviceRX:
normal = false; writable = false; executable = true; break;
case kARMMMUDeviceRW:
normal = false; writable = true; executable = false; break;
case kARMMMUNormalR:
normal = true; writable = false; executable = false; break;
case kARMMMUNormalRX:
normal = true; writable = false; executable = true; break;
case kARMMMUNormalRW:
normal = true; writable = true; executable = false; break;
default:
panic("Bad attr %d", (int) attr);
}
// Always set Access Flag, Non-Secure and Valid.
uint64_t value = ARM_LPAE_AF | ARM_LPAE_NS | ARM_LPAE_VALID;
if (level < LAST_TABLE_LEVEL) {
value |= ARM_LPAE_TYPE_L0L1L2BLOCK;
} else {
value |= ARM_LPAE_TYPE_L3BLOCK;
}
uint64_t sh, attr_indx;
if (normal) {
sh = SH_OUTER_MEMORY;
attr_indx = CACHE_ATTRINDX_WRITEBACK;
} else {
sh = SH_NONE;
attr_indx = CACHE_ATTRINDX_DISABLE;
}
value |= ARM_LPAE_SH(sh);
value |= ARM_LPAE_ATTRINDX(attr_indx);
uint64_t ap = writable ? 0 : 2;
value |= ARM_LPAE_AP(ap);
if (!executable) {
value |= ARM_LPAE_PXN | ARM_LPAE_XN;
}
return value;
}
static uint64_t get_virt_size_bytes(void)
{
return 1ULL << get_virt_address_bits();
}
static uint64_t get_phys_size_bytes(void)
{
return 1ULL << 40;
}
static size_t get_level_shift(unsigned level)
{
assert_valid_level(level);
switch (get_page_granule_shift()) {
case 12: return 39 - (level * 9);
case 14: return 47 - (level * 11);
case 16: return 55 - (level * 13);
default: panic("Granule 2^%u not supported\n",
get_page_granule_shift());
}
}
static size_t get_level_entries(unsigned level)
{
assert_valid_level(level);
// 1 granule per sub-table, 8 bytes per entry.
return ((size_t) 1) << (get_page_granule_shift() - 3);
}
static addr_t tt_alloc(unsigned level)
{
// Allocate a translation table. The start level was
// allocated as tt_top_level in arm_mmu_init and should not be
// requested to be allocated. All levels are the
// same size: one granule.
RELEASE_ASSERT(level > get_start_level() && level <= LAST_TABLE_LEVEL);
size_t bytes = ((size_t) 1) << get_page_granule_shift();
mmu_spew("Allocate L%u size 0x%llx\n", level,
(unsigned long long) bytes);
if (bytes > tt_alloc_end || tt_alloc_next > tt_alloc_end - bytes) {
panic("Out of table allocation space L%u\n", level);
}
addr_t ret = tt_alloc_next;
// Alignment is guaranteed by arm_mmu_init() and all
// allocations being the same size (1 granule), but it's cheap
// to double-check allocation alignment.
if ((ret & (bytes - 1)) != 0) {
panic("Bad aligned pte alloc 0x%llx\n",
(unsigned long long) ret);
}
tt_alloc_next += bytes;
mmu_spew("Allocated L%u size 0x%llx at 0x%llx\n",
level, (unsigned long long) bytes, (unsigned long long) ret);
return ret;
}
static size_t map_at_level(unsigned level, addr_t table_base,
addr_t vaddr, addr_t paddr, size_t size,
arm_mmu_extended_attr_t attr,
bool blank_table)
{
mmu_spew("map_at_level(level=%u,\n"
" table_base=0x%llx,\n"
" vaddr=0x%llx,\n"
" paddr=0x%llx,\n"
" size=0x%llx,\n"
" attr=%u\n",
level, (unsigned long long) table_base,
(unsigned long long) vaddr, (unsigned long long) paddr,
(unsigned long long) size, (unsigned) attr);
// Check this mapping is bounded by virtual and physical address limits.
assert_valid_level(level);
RELEASE_ASSERT(size <= get_virt_size_bytes() &&
vaddr <= get_virt_size_bytes() - size);
RELEASE_ASSERT(size <= get_phys_size_bytes() &&
paddr <= get_phys_size_bytes() - size);
// Calculate constants about this translation level.
size_t level_shift = get_level_shift(level);
size_t level_entries = get_level_entries(level);
size_t level_size = 1ULL << level_shift;
size_t level_mask = level_size - 1;
bool permit_block = level_permits_blocks(level);
size_t index = (vaddr >> level_shift) & (level_entries - 1);
mmu_spew("shift:%d entries:%d size:0x%llx mask:0x%llx "
"block:%d index:%d\n",
(int) level_shift,
(int) level_entries,
(unsigned long long) level_size,
(unsigned long long) level_mask,
(int) permit_block,
(int) index);
// Can we make block entries here? Must be permitted at this
// level, have enough bytes remaining, and both virtual and
// physical addresses aligned to a block.
if (permit_block &&
size >= level_size &&
((vaddr | paddr) & level_mask) == 0) {
// Map contiguous blocks.
mmu_spew("Array of blocks\n");
size_t mapped_size = 0;
size_t remaining_size = size;
// Common block flags for all entries at this level.
uint64_t block_flags = get_block_flags(level, attr);
while (remaining_size >= level_size && index < level_entries) {
// Check the existing entry is unused.
uint64_t entry = get_table_entry(level, table_base,
index);
if (entry != 0) {
// Not difficult but no use case.
panic("Remapping an existing L%u at 0x%016llx",
level, (unsigned long long) vaddr);
}
// Form an entry.
uint64_t ent = block_flags | paddr;
// Write a block entry to the table.
set_table_entry(level, table_base, index, ent);
// Next index.
mapped_size += level_size;
remaining_size -= level_size;
paddr += level_size;
vaddr += level_size;
++index;
}
// Must make forward progress... and not too much.
RELEASE_ASSERT(mapped_size > 0 && mapped_size <= size);
return mapped_size;
} else {
// Sub-divide into a next level table.
mmu_spew("Sub-divide\n");
// Only so much granularity available.
RELEASE_ASSERT(level < LAST_TABLE_LEVEL);
// Get the existing entry.
uint64_t entry = blank_table ? 0 : get_table_entry(level, table_base, index);
if ((entry & ARM_LPAE_VALID) &&
(entry & ARM_LPAE_TYPE_MASK) == ARM_LPAE_TYPE_L0L1L2BLOCK) {
// Not hard but no use case.
panic("Breaking down blocks not implemented");
}
unsigned sub_level = level + 1;
bool blank_sub_table;
addr_t sub_base;
if (entry & ARM_LPAE_VALID) {
mmu_spew("Existing entry\n");
sub_base = entry & ARM_LPAE_TABLE_MASK;
blank_sub_table = false;
} else {
mmu_spew("Allocating sub-level table\n");
sub_base = tt_alloc(sub_level);
// Form an entry.
uint64_t ent = get_table_flags() | sub_base;
// Store an entry pointing to the sub-level table.
set_table_entry(level, table_base, index, ent);
blank_sub_table = true;
}
// Recurse at next level.
return map_at_level(sub_level, sub_base,
vaddr, paddr, size, attr, blank_sub_table);
}
}
void arm_mmu_map_range(addr_t vaddr, addr_t paddr, size_t size,
arm_mmu_extended_attr_t attr)
{
// Ensure all addresses and sizes are at least L3 aligned.
size_t l3_align = ((size_t) 1) << get_level_shift(LAST_TABLE_LEVEL);
RELEASE_ASSERT(((vaddr | paddr | size) & (l3_align - 1)) == 0);
while (size > 0) {
// Map at the top level first, allowing the mapper function
// to break it down into smaller chunks as necessary.
size_t mapped = map_at_level(get_start_level(),
(addr_t) tt_top_level,
vaddr, paddr, size, attr, false);
RELEASE_ASSERT(mapped <= size);
size -= mapped;
vaddr += mapped;
paddr += mapped;
}
if ((arm_read_sctlr() & SCTLR_M_ENABLED) != 0) {
arm_flush_tlbs();
}
}
void arm_mmu_map_ro(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUNormalR);
}
void arm_mmu_map_rw(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUNormalRW);
}
void arm_mmu_map_rx(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUNormalRX);
}
void arm_mmu_map_device_ro(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUDeviceR);
}
void arm_mmu_map_device_rw(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUDeviceRW);
}
void arm_mmu_map_device_rx(addr_t addr, size_t size)
{
arm_mmu_map_range(addr, addr, size, kARMMMUDeviceRX);
}
void arm_mmu_init(bool resume)
{
// Setup memory attributes.
arm_write_mair(get_mair());
// Setup translation control register.
arm_write_tcr(get_tcr());
/*
* Sub-level page table allocations starts in the book-keeping
* region after all stacks, rounded up. Allocation rounded down.
*/
size_t granule_mask = (((size_t) 1) << get_page_granule_shift()) - 1;
addr_t page_tables_base;
size_t page_tables_size;
mmu_get_memmap(&page_tables_base,
&page_tables_size);
RELEASE_ASSERT((page_tables_base & granule_mask) == 0);
RELEASE_ASSERT((page_tables_size & granule_mask) == 0);
tt_alloc_start = page_tables_base;
tt_alloc_next = tt_alloc_start;
tt_alloc_end = (page_tables_base + page_tables_size) & ~granule_mask;
// allocate top-level page table
tt_top_level = (uint64_t *)tt_alloc_start;
tt_alloc_next += 1 << get_page_granule_shift();
// Defer to platform code for the memory map setup.
platform_mmu_setup(resume);
// Write the translation table base.
arm_write_ttbr0(tt_top_level);
// Flush TLBs.
arm_flush_tlbs();
}
#ifdef TEST
// static->global stubs for mmu_test.c
uint64_t *mmu_get_tt_top_level(void) { return tt_top_level; }
unsigned mmu_get_start_level(void) { return get_start_level(); }
uint64_t mmu_get_tcr(void) { return get_tcr(); }
uint64_t mmu_tt_alloc(unsigned level) { return tt_alloc(level); }
size_t mmu_get_level_entries(unsigned level) {
return get_level_entries(level);
}
uint64_t mmu_get_table_flags(void) {
return get_table_flags();
}
uint64_t mmu_get_block_flags(unsigned level, arm_mmu_extended_attr_t attr) {
return get_block_flags(level, attr);
}
size_t mmu_map_at_level(unsigned level, addr_t table_base,
addr_t vaddr, addr_t paddr, size_t size,
arm_mmu_extended_attr_t attr)
{
return map_at_level(level, table_base, vaddr, paddr, size, attr, false);
}
void mmu_get_tt_alloc_range(addr_t *start, addr_t *next, addr_t *end)
{
*start = tt_alloc_start;
*next = tt_alloc_next;
*end = tt_alloc_end;
}
void mmu_reset_state(void)
{
tt_top_level = 0;
tt_alloc_start = 0;
tt_alloc_next = 0;
tt_alloc_end = 0;
}
#endif // defined(TEST)
+846
View File
@@ -0,0 +1,846 @@
/*
* Copyright (C) 2014 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 <stdbool.h>
#include <assert.h>
#include <inttypes.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arch/arm/arm.h>
#include <arch/arm64/proc_reg.h>
#define VERBOSITY FAILURE
#define FAILURE 0
#define INFO 1
#define SPEW 2
static size_t tests_run, tests_passed;
enum Reason {
REASON_OK = 0,
REASON_EXPECTED_PANIC,
REASON_UNEXPECTED_PANIC,
REASON_PARAMS,
REASON_LEVEL,
REASON_OOM,
REASON_PTE_ALIGNMENT,
REASON_PTE_BASE,
REASON_PTE_INDEX,
REASON_PTE_ACCESS,
REASON_PTE_MISMATCH
};
static void test_unwind(enum Reason reason) __attribute__((noreturn));
#define TEST_ASSERT(reason, c) \
do { \
if (!(c)) { \
printf("!!! Test assertion failure: %s\n", \
#c ); \
test_unwind(reason); \
} \
} while (0)
struct State {
// Environment constants for an individual test.
const char *test_name;
const char *expect_panic_func;
const char *expect_panic_substr;
size_t level_entries[4];
void *page_tables_base;
size_t page_tables_size;
size_t total_stack_size;
unsigned page_granule_shift;
jmp_buf jmp_env;
// Updated during test.
bool arm_flush_tlbs_called;
// Callbacks from test.
void (^mmu_setup_func)();
void (^get_table_entry_hook)();
void (^set_table_entry_hook)();
};
static struct State state;
unsigned get_page_granule_shift(void) { return state.page_granule_shift; }
void mmu_get_memmap(addr_t *page_tables_base,
size_t *page_tables_size)
{
*page_tables_base = (addr_t) state.page_tables_base;
*page_tables_size = state.page_tables_size;
}
// Access to mmu.c static functions and variables.
uint64_t *mmu_get_tt_top_level(void);
unsigned mmu_get_start_level(void);
uint64_t mmu_get_tcr(void);
addr_t mmu_tt_alloc(unsigned level);
size_t mmu_get_level_entries(unsigned level);
uint64_t mmu_get_table_flags(void);
uint64_t mmu_get_block_flags(unsigned level, arm_mmu_extended_attr_t attr);
size_t mmu_map_at_level(unsigned level, addr_t table_base,
addr_t vaddr, addr_t paddr, size_t size,
arm_mmu_extended_attr_t attr);
void mmu_get_tt_alloc_range(addr_t *start, addr_t *next, addr_t *end);
void mmu_reset_state(void);
const char *reason_to_string(int reason)
{
switch (reason) {
case REASON_OK: return "OK";
case REASON_EXPECTED_PANIC: return "Expected panic() called";
case REASON_UNEXPECTED_PANIC: return "Unexpected panic() called";
case REASON_PARAMS: return "Bad parameters detected";
case REASON_LEVEL: return "Invalid level used";
case REASON_OOM: return "Test ran out of memory for structures";
case REASON_PTE_ALIGNMENT: return "Bad page table alignment";
case REASON_PTE_BASE: return "Page table base does not match allocated";
case REASON_PTE_INDEX: return "Page table index out of bounds";
case REASON_PTE_ACCESS: return "Page table unexpected access";
case REASON_PTE_MISMATCH: return "Page table value mismatch";
default:
printf("Bad reason code %d\n", (int) reason);
abort();
}
}
void mmu_printf(int verbosity, const char *fmt, ...)
{
if (VERBOSITY >= verbosity) {
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
}
}
static void test_unwind(enum Reason reason)
{
assert(reason != REASON_OK);
longjmp(state.jmp_env, (int) reason);
}
void _panic(const char *func, const char *fmt, ...)
{
char *buf = malloc(4096);
va_list va;
va_start(va, fmt);
vsnprintf(buf, 4096, fmt, va);
va_end(va);
bool expected = state.expect_panic_func && state.expect_panic_substr &&
strstr(func, state.expect_panic_func) != NULL &&
strstr(buf, state.expect_panic_substr) != NULL;
if (!expected) {
mmu_printf(FAILURE, "!!! Unexpected panic in function %s: %s\n", func, buf);
} else {
mmu_printf(INFO, "Expected panic in function %s: %s\n", func, buf);
}
free(buf);
if (expected) {
test_unwind(REASON_EXPECTED_PANIC);
} else if (strstr(buf, "Out of table allocation space")) {
test_unwind(REASON_OOM);
} else {
test_unwind(REASON_UNEXPECTED_PANIC);
}
}
static void expect_panic(const char *func, const char *substr)
{
state.expect_panic_func = func;
state.expect_panic_substr = substr;
}
uint64_t check_valid_index(unsigned level, addr_t table_base, size_t index)
{
if (level < mmu_get_start_level() || level > 3) {
mmu_printf(FAILURE, "L%u invalid level\n", level);
test_unwind(REASON_LEVEL);
}
void *p = NULL;
size_t table_size =
mmu_get_level_entries(level) * sizeof(uint64_t);
size_t table_entries = mmu_get_level_entries(level);
uint64_t alloc_start, alloc_next, alloc_end;
mmu_get_tt_alloc_range(&alloc_start, &alloc_next, &alloc_end);
if (table_base < alloc_start ||
table_size > alloc_next ||
table_base > alloc_next - table_size) {
mmu_printf(FAILURE, "L%u base 0x%" PRIx64 " size 0x%" PRIx64
" outside allocated space\n",
level,
(uint64_t) table_base,
(uint64_t) table_size);
test_unwind(REASON_PTE_BASE);
}
if (index > table_entries) {
mmu_printf(FAILURE, "L%u entry %u >= table_entries %u\n",
level, (unsigned) index,
(unsigned) table_entries);
test_unwind(REASON_PTE_INDEX);
}
p = (void *) (table_base + index * 8);
uint64_t result;
memcpy(&result, p, sizeof(result));
return result;
}
static void get_table_entry_internal(unsigned level, addr_t table_base,
size_t index)
{
mmu_printf(SPEW, "get_table_entry(%u, 0x%" PRIx64 ", %u) ",
level, (uint64_t) table_base, (unsigned) index);
uint64_t result = check_valid_index(level, table_base, index);
mmu_printf(SPEW, "= 0x%016" PRIx64 "\n", result);
}
void get_table_entry_hook(unsigned level, addr_t table_base, size_t index)
{
if (state.get_table_entry_hook) {
state.get_table_entry_hook(level, table_base, index);
return;
} else {
get_table_entry_internal(level, table_base, index);
}
}
static void set_table_entry_internal(unsigned level, addr_t table_base,
size_t index, uint64_t value)
{
mmu_printf(SPEW, "set_table_entry(%u, 0x%" PRIx64 ", %u, "
"0x%" PRIx64 ") ",
level, (uint64_t) table_base, (unsigned) index,
value);
uint64_t old = check_valid_index(level, table_base, index);
mmu_printf(SPEW, " was 0x%016" PRIx64 "\n", old);
}
void set_table_entry_hook(unsigned level, addr_t table_base, size_t index,
uint64_t value)
{
if (state.set_table_entry_hook) {
state.set_table_entry_hook(level, table_base, index, value);
return;
} else {
set_table_entry_internal(level, table_base, index, value);
}
}
// Mock HAL.
uint64_t arm_read_sctlr(void)
{
mmu_printf(INFO, "arm_read_sctlr()\n");
return 0;
}
void arm_write_mair(uint64_t mair)
{
mmu_printf(INFO, "arm_write_mair(0x%016" PRIx64 ")\n", (uint64_t) mair);
}
void arm_write_tcr(uint64_t tcr)
{
mmu_printf(INFO, "arm_write_tcr(0x%016" PRIx64 ")\n", (uint64_t) tcr);
}
void arm_write_ttbr0(void *ttbr0)
{
mmu_printf(INFO, "arm_write_ttbr0(%p)\n", ttbr0);
if ((addr_t) ttbr0 != (addr_t) mmu_get_tt_top_level()) {
mmu_printf(FAILURE, "TTBR0 written with %p expected %p\n",
ttbr0, mmu_get_tt_top_level());
test_unwind(REASON_PTE_BASE);
}
}
void arm_flush_tlbs(void)
{
mmu_printf(INFO, "arm_flush_tlbs()\n");
state.arm_flush_tlbs_called = true;
}
void platform_mmu_setup(bool resume)
{
(void) resume;
uint64_t alloc_start, alloc_next, alloc_end;
mmu_get_tt_alloc_range(&alloc_start, &alloc_next, &alloc_end);
mmu_printf(INFO, "platform_mmu_setup(%d)\n", (int) resume);
mmu_printf(INFO, "tt_top_level = %p\n", mmu_get_tt_top_level());
mmu_printf(INFO, "page_tables_base = %p\n", state.page_tables_base);
mmu_printf(INFO, "page_tables_size = 0x%" PRIx64 "\n",
(uint64_t) state.page_tables_size);
mmu_printf(INFO, "tt_alloc_start = 0x%" PRIx64 "\n"
"tt_alloc_next = 0x%" PRIx64 "\n"
"tt_alloc_end = 0x%" PRIx64 "\n",
(uint64_t) alloc_start,
(uint64_t) alloc_next,
(uint64_t) alloc_end);
if (state.mmu_setup_func) {
state.mmu_setup_func();
}
}
// Test setup functions.
static void reset_state(void)
{
mmu_reset_state();
assert(state.page_tables_base == NULL); // Prevent leak.
memset(&state, 0, sizeof(state));
}
static void mmu_setup_flat(void)
{
uint64_t io_base = 0x200000000ULL;
uint64_t io_size = 256ULL * 1024 * 1024;
uint64_t sdram_base = 0x800000000ULL;
uint64_t sdram_len = 1ULL << 30;
arm_mmu_map_rw(sdram_base, sdram_len);
arm_mmu_map_device_rw(io_base, io_size);
}
static void mmu_setup_fail_remap_existing(void)
{
uint64_t io_base = 0x200000000ULL;
uint64_t io_size = 256ULL * 1024 * 1024;
arm_mmu_map_rw(io_base, io_size);
// Map again
arm_mmu_map_device_rw(io_base, io_size);
}
static void mmu_setup_fail_breaking_down(void)
{
uint64_t io_base = 0x200000000ULL;
uint64_t io_size = 256ULL * 1024 * 1024;
arm_mmu_map_rw(io_base, io_size);
// Map one L3 page again
arm_mmu_map_rw(io_base, 4096);
}
static void mmu_setup_misaligned(void)
{
uint64_t sdram_base = 0x800000000ULL;
uint64_t sdram_len = 1ULL << 30;
arm_mmu_map_rw(sdram_base, sdram_len + 512);
}
static void test_delete(void)
{
uint64_t alloc_start, alloc_next, alloc_end;
mmu_get_tt_alloc_range(&alloc_start, &alloc_next, &alloc_end);
mmu_printf(INFO, "Allocation space used: 0x%" PRIx64 "\n",
alloc_next - alloc_start);
mmu_printf(INFO, "Allocation space remaining: 0x%" PRIx64 "\n",
alloc_end - alloc_next);
if (state.page_tables_base) {
free(state.page_tables_base);
state.page_tables_base = NULL;
}
reset_state();
}
static int mmu_test(void)
{
mmu_printf(INFO, "Test \"%s\" running\n", state.test_name);
int ret = posix_memalign(&state.page_tables_base,
1 << state.page_granule_shift,
state.page_tables_size);
assert(ret == 0);
memset(state.page_tables_base, 0, state.page_tables_size);
arm_mmu_init(false);
// Calls back on platform_mmu_setup(resume)
if (state.arm_flush_tlbs_called) {
return true;
} else {
mmu_printf(FAILURE, "!!! arm_flush_tlbs() was not called\n");
return false;
}
}
static void do_test(enum Reason expect_reason, int (^test_func)(void))
{
assert(state.test_name != NULL);
mmu_printf(INFO, "----------------------------------------"
"--------------------------------------\n");
mmu_printf(INFO, "Test: %s\n", state.test_name);
// Increment number of tests run.
++tests_run;
// Set a jump environment for panic/abort exit path.
int reason_code = setjmp(state.jmp_env);
if (reason_code != 0) {
// Returns non-zero if longjmp() invoked to return here.
if (reason_code == (int) expect_reason) {
// Failure for an expected reason: exercising error
// detection.
mmu_printf(INFO, "Test \"%s\" aborted for expected reason: %s\n",
state.test_name,
reason_to_string(expect_reason));
++tests_passed;
} else {
mmu_printf(FAILURE, "!!! Test \"%s\" failed: %s\n",
state.test_name,
reason_to_string(reason_code));
mmu_printf(FAILURE, "!!! Expected outcome: %s\n",
reason_to_string(expect_reason));
}
test_delete();
reset_state();
return;
}
if (test_func()) {
mmu_printf(INFO, "Test \"%s\" completed, passed\n",
state.test_name);
++tests_passed;
} else {
mmu_printf(FAILURE, "!!! Test \"%s\" failed at completion\n",
state.test_name);
mmu_printf(FAILURE, "!!! Expected outcome: %s\n",
reason_to_string(expect_reason));
}
test_delete();
reset_state();
}
static void setup_standard_granule(size_t granule)
{
switch (granule) {
case 4096:
state.page_granule_shift = 12;
state.page_tables_size = 4096 * 4;
break;
case 16384:
state.page_granule_shift = 14;
state.page_tables_size = 16384 * 4;
break;
case 65536:
state.page_granule_shift = 16;
state.page_tables_size = 65536 * 4;
break;
default:
mmu_printf(FAILURE, "Bad granule %u\n", (unsigned) granule);
abort();
}
}
static void test_granule(size_t bytes)
{
state.mmu_setup_func = ^{ mmu_setup_flat(); };
setup_standard_granule(bytes);
do_test(REASON_OK, ^{ return mmu_test(); });
}
static void test_granule_4kb(void)
{
state.test_name = "4KB granule";
test_granule(4096);
}
static void test_granule_16kb(void)
{
state.test_name = "16KB granule";
test_granule(16384);
}
static void test_granule_64kb(void)
{
state.test_name = "64KB granule";
test_granule(65536);
}
static void test_fail_oom(void)
{
state.test_name = "Detect out-of-memory PTE allocation";
state.mmu_setup_func = ^{ mmu_setup_flat(); };
setup_standard_granule(4096);
// Too small.
state.page_tables_size = 16384;
expect_panic("tt_alloc", "Out of table allocation space L2");
do_test(REASON_EXPECTED_PANIC, ^{ return mmu_test(); });
}
static void test_fail_range_misaligned(void)
{
state.test_name = "Detect misaligned mapping request";
state.mmu_setup_func = ^{ mmu_setup_misaligned(); };
setup_standard_granule(4096);
// Expect vaddr, paddr, size to misaligned.
expect_panic("arm_mmu_map_range", "vaddr | paddr | size");
do_test(REASON_EXPECTED_PANIC, ^{ return mmu_test(); });
}
static void test_fail_bad_granule(void)
{
state.test_name = "Detect bad granule size";
state.mmu_setup_func = ^{
// Alter the granule to an illegal value.
++state.page_granule_shift;
mmu_setup_flat();
};
setup_standard_granule(4096);
expect_panic("get_level_shift", "Granule 2^13");
do_test(REASON_EXPECTED_PANIC, ^{ return mmu_test(); });
}
static void test_fail_remap_existing(void)
{
state.test_name = "Detect remapping existing page";
state.mmu_setup_func = ^{ mmu_setup_fail_remap_existing(); };
setup_standard_granule(4096);
expect_panic("map_at_level", "Remapping an existing L2");
do_test(REASON_EXPECTED_PANIC, ^{ return mmu_test(); });
}
static void test_fail_breaking_down(void)
{
state.test_name = "Detect breaking down existing mapping";
state.mmu_setup_func = ^{ mmu_setup_fail_breaking_down(); };
setup_standard_granule(4096);
expect_panic("map_at_level", "Breaking down");
do_test(REASON_EXPECTED_PANIC, ^{ return mmu_test(); });
}
static void test_get_tcr(void)
{
state.test_name = "get_tcr()";
do_test(REASON_OK,
^{
state.page_granule_shift = 12;
mmu_get_tcr();
state.page_granule_shift = 14;
mmu_get_tcr();
state.page_granule_shift = 16;
mmu_get_tcr();
return true;
});
}
static void test_fail_get_tcr_bad_granule(void)
{
state.test_name = "Detect get_tcr() with bad granule";
expect_panic("get_tcr", "Bad granule");
state.page_granule_shift = 13;
do_test(REASON_EXPECTED_PANIC, ^{ mmu_get_tcr(); return false; });
}
static void test_get_block_flags_for_level(unsigned level)
{
// [63:59] SBZ
// [58:55] S/W use SBZ
// [54:53] XN,PXN = execute never, 0 for RX, 3 for R/RW
// [52] Contiguous hint, SBZ
// [51:12] SBZ and address bits, also SBZ
// [11] nG - non-global, we don't use ASID - SBZ
// [10] AF - access flag, should set - SBO
// [9:8] SH - shareability - 0 for device, 2 for normal
// [7:6] AP - access permission - 0 for RW, 2 for RO
// [5] NS - non-secure, should set - SBO
// [4:2] AttrIndx - 0 for device, 1 for normal
// [1] Walk - L0,L1,L2 0=Block; L3 1=Block
// [0] V - 0=fault, 1=valid
const uint64_t sbo = (1 << 10) | (1 << 5) | (1 << 0);
const uint64_t normal = (2 << 8) | (1 << 2);
const uint64_t device = (0 << 8) | (0 << 2);
const uint64_t read_write = 0 << 6;
const uint64_t read_only = 2 << 6;
const uint64_t execute = 0ULL << 53;
const uint64_t no_execute = 3ULL << 53;
static const struct {
arm_mmu_extended_attr_t attr;
uint64_t expect;
} tests[] = {
{ kARMMMUDeviceR, sbo | device | read_only | no_execute },
{ kARMMMUDeviceRX, sbo | device | read_only | execute },
{ kARMMMUDeviceRW, sbo | device | read_write | no_execute },
{ kARMMMUNormalR, sbo | normal | read_only | no_execute },
{ kARMMMUNormalRX, sbo | normal | read_only | execute },
{ kARMMMUNormalRW, sbo | normal | read_write | no_execute },
};
for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
arm_mmu_extended_attr_t attr = tests[i].attr;
uint64_t expect = tests[i].expect;
if (level == 3) {
expect |= 1 << 1; // "Walk" flag
}
uint64_t value = mmu_get_block_flags(level, attr);
if (value != expect) {
mmu_printf(FAILURE, "get_block_flags level %u test %u enum %u\n",
level, (unsigned) i, (unsigned) attr);
mmu_printf(FAILURE, "got 0x%" PRIx64 "\n", value);
mmu_printf(FAILURE, "expect 0x%" PRIx64 "\n", expect);
test_unwind(REASON_PTE_MISMATCH);
}
}
}
static void test_get_block_flags(void)
{
state.test_name = "get_block_flags()";
state.page_granule_shift = 12;
do_test(REASON_OK, ^{
for (unsigned level = 1; level <= 3; ++level) {
test_get_block_flags_for_level(level);
}
return true;
});
}
static void test_get_table_flags(void)
{
state.test_name = "get_tte_flags()";
state.page_granule_shift = 12;
// [63] NS
// [62:61] AP
// [60] XN
// [59] PXN
// [58:52] ignored
// [51:48] zero, sbz
// [47:12] TableOutputAddress
// [11:2] ignored
// [1] type=1, sbo
// [0] valid=1, sbo
const uint64_t expect = (1ULL << 63) | (1ULL << 1) | (1ULL << 0);
do_test(REASON_OK, ^{
uint64_t value = mmu_get_table_flags();
if (value != expect) {
mmu_printf(FAILURE, "get_table_flags() mismatch\n");
mmu_printf(FAILURE, "Got 0x%" PRIx64 "\n", value);
mmu_printf(FAILURE, "Expect 0x%" PRIx64 "\n", expect);
test_unwind(REASON_PTE_MISMATCH);
}
return true;
});
}
static void test_fail_get_block_flags_bad_attr(void)
{
state.test_name = "Detect get_block_flags() bad attribute";
state.page_granule_shift = 12;
expect_panic("get_block_flags", "Bad attr");
do_test(REASON_EXPECTED_PANIC,
^{ mmu_get_block_flags(3, -1); return false; });
}
static void test_fail_get_block_flags_bad_level(void)
{
state.test_name = "Detect get_pte_flags() bad level";
state.page_granule_shift = 16;
expect_panic("get_block_flags", "level_permits_blocks");
// Should not allow a block at L1 with 64KB granule.
do_test(REASON_EXPECTED_PANIC,
^{ mmu_get_block_flags(1, kARMMMUNormalRW); return false; });
}
static void test_tt_alloc(unsigned granule_shift)
{
state.test_name = "tt_alloc()";
state.page_granule_shift = granule_shift;
state.page_tables_size = (1 << granule_shift) * 3;
state.mmu_setup_func = ^{};
do_test(REASON_OK,
^{
arm_mmu_init(false);
if (granule_shift == 12)
mmu_tt_alloc(2);
mmu_tt_alloc(3);
return true;
});
}
static void test_tt_alloc_bad_level(void)
{
state.test_name = "Detect tt_alloc() bad level";
state.page_granule_shift = 14;
state.page_tables_size = 16384 * 3;
state.mmu_setup_func = ^{};
expect_panic("tt_alloc", "level > ");
do_test(REASON_EXPECTED_PANIC,
^{
arm_mmu_init(false);
mmu_tt_alloc(1);
return false;
});
}
static void test_tt_alloc_bad_alignment(void)
{
state.test_name = "Detect tt_alloc() bad alignment";
state.page_granule_shift = 14;
state.page_tables_size = 65536 * 3; // Enough space.
state.mmu_setup_func = ^{};
expect_panic("tt_alloc", "Bad aligned pte alloc");
do_test(REASON_EXPECTED_PANIC,
^{
arm_mmu_init(false);
mmu_tt_alloc(3);
// Allocation is aligned, so only way to trip it up
// is to artificially tamper with the granule.
state.page_granule_shift = 16;
mmu_tt_alloc(3);
return false;
});
}
static void test_map_at_top_level_large(void)
{
state.test_name = "map_at_level() at top level traverses only L1";
setup_standard_granule(4096);
__block uint64_t alloc_start, alloc_next, alloc_end;
state.mmu_setup_func = ^{
mmu_get_tt_alloc_range(&alloc_start, &alloc_next, &alloc_end);
mmu_map_at_level(1,
(addr_t) mmu_get_tt_top_level(),
1ULL << 30, 1ULL << 30, 1ULL << 30,
kARMMMUNormalRW);
};
__block size_t calls = 0;
state.set_table_entry_hook = ^(unsigned level,
uint64_t base,
size_t index,
uint64_t value) {
(void) value;
++calls;
mmu_printf(INFO, "calls:%u %u 0x%" PRIx64 " 0x%" PRIx64
" 0x%" PRIx64 "\n",
(unsigned) calls,
level, base, (uint64_t) index, value);
if (calls == 1) {
if (level != 1 ||
base != (uint64_t) mmu_get_tt_top_level() ||
index != 1) {
mmu_printf(FAILURE, "Did not write L0 index 0\n");
test_unwind(REASON_PTE_ACCESS);
}
} else {
mmu_printf(FAILURE, "Too many calls to get_table_entry()\n");
test_unwind(REASON_PTE_ACCESS);
}
};
do_test(REASON_OK,
^{
if (!mmu_test()) {
return false;
}
return true;
});
}
static void test_map_at_l3(void)
{
state.test_name = "map_at_level() at l3";
setup_standard_granule(16384);
__block uint64_t alloc_start = 0, alloc_next = 0, alloc_end = 0;
__block uint64_t l3_base = 0;
state.mmu_setup_func = ^{
mmu_get_tt_alloc_range(&alloc_start, &alloc_next, &alloc_end);
l3_base = mmu_tt_alloc(3);
mmu_map_at_level(3, l3_base,
(1ULL << 30) + 16384 * 3,
16384 * 7,
16384,
kARMMMUDeviceRW);
};
__block size_t calls = 0;
state.set_table_entry_hook = ^(unsigned level,
uint64_t base,
size_t index,
uint64_t value) {
(void) value;
++calls;
mmu_printf(INFO, "calls:%u %u 0x%" PRIx64 " 0x%" PRIx64
" 0x%" PRIx64 "\n",
(unsigned) calls,
level, base, (uint64_t) index, value);
if (calls == 1) {
if (level != 3 ||
base != l3_base ||
index != 3) {
mmu_printf(FAILURE, "Did not write L3 index 3\n");
test_unwind(REASON_PTE_ACCESS);
}
} else {
mmu_printf(FAILURE, "Too many calls to get_table_entry()\n");
test_unwind(REASON_PTE_ACCESS);
}
};
do_test(REASON_OK,
^{
if (!mmu_test()) {
return false;
}
return true;
});
}
int main()
{
reset_state();
test_granule_4kb();
test_granule_16kb();
test_granule_64kb();
test_fail_oom();
test_fail_range_misaligned();
test_fail_bad_granule();
test_fail_remap_existing();
test_fail_breaking_down();
test_get_tcr();
// test_fail_get_tcr_bad_granule(); !!!FIXME!!! <rdar://problem/19225114> Unexpected panic in function get_virt_address_bits: Bad granule
test_get_block_flags();
test_get_table_flags();
test_fail_get_block_flags_bad_attr();
test_fail_get_block_flags_bad_level();
test_tt_alloc(12);
test_tt_alloc(14);
test_tt_alloc(16);
test_tt_alloc_bad_level();
test_tt_alloc_bad_alignment();
test_map_at_top_level_large();
test_map_at_l3();
mmu_printf(INFO, "%" PRIu64 "/%" PRIu64 " tests passed\n",
(uint64_t) tests_passed, (uint64_t) tests_run);
assert(tests_passed <= tests_run);
if (tests_passed == tests_run) {
mmu_printf(INFO, "Pass\n");
return 0;
} else {
mmu_printf(INFO, "!!! Fail\n");
return 1;
}
}
+176
View File
@@ -0,0 +1,176 @@
# Copyright (C) 2011-2014 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.
#
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
ARCH_ARMV8_CPUS := apple-cyclone apple-typhoon apple-typhoon-capri apple-twister apple-hurricane-zephyr
################################################################################
# Per-CPU configuration
################################################################################
#
# Apple Cyclone/Typhoon
#
ifneq (,$(filter $(ARCH_ARMV8_CPUS),$(ARM_CPU)))
ARM_ARCH ?= arm64
ARM_ARCH_OPTIONS := ARCH_ARMv8=1 WITH_VFP=1 WITH_VFP_ALWAYS_ON=1
OPTIONS += \
CPU_APPLE_CYCLONE=1 \
L1_CACHELINE_SIZE=64 \
L1_CACHELINE_SHIFT=6 \
CPU_CACHELINE_SIZE=L1_CACHELINE_SIZE \
CPU_CACHELINE_SHIFT=L1_CACHELINE_SHIFT \
WITH_HW_TIMER=1
ALL_OBJS += \
$(LOCAL_DIR)/mmu.o \
$(LOCAL_DIR)/timer.o
ifneq (,$(filter apple-cyclone apple-typhoon,$(ARM_CPU)))
WITH_EL3 := 1
OPTIONS += \
L1_CACHEINDEX_SHIFT=9 \
L1_CACHEWAY_SHIFT=1 \
L2_CACHE_SIZE=1048576 \
L2_CACHEINDEX_SHIFT=11 \
L2_CACHEWAY_SHIFT=3 \
L2_CACHEWAY_COUNT=8 \
L2_CACHELINE_SHIFT=6 \
PAGE_GRANULE_SHIFT=12 \
PAGE_SIZE=4096 \
WITH_EL3=1 \
WITH_MCC_AS_RAM=1
#4k-algined linker pages
GLOBAL_LDFLAGS += -Wl,-segalign,0x1000
else ifneq (,$(filter apple-typhoon-capri,$(ARM_CPU)))
WITH_EL3 := 1
OPTIONS += \
L1_CACHEINDEX_SHIFT=9 \
L1_CACHEWAY_SHIFT=1 \
L2_CACHE_SIZE=2097152 \
L2_CACHEINDEX_SHIFT=12 \
L2_CACHEWAY_SHIFT=3 \
L2_CACHEWAY_COUNT=8 \
L2_CACHELINE_SHIFT=6 \
PAGE_GRANULE_SHIFT=12 \
PAGE_SIZE=4096 \
WITH_EL3=1 \
WITH_MCC_AS_RAM=1
#4k-algined linker pages
GLOBAL_LDFLAGS += -Wl,-segalign,0x1000
else ifneq (,$(filter apple-twister,$(ARM_CPU)))
WITH_EL3 := 1
OPTIONS += \
L1_CACHEINDEX_SHIFT=8 \
L1_CACHEWAY_SHIFT=2 \
L2_CACHE_SIZE=3145728 \
L2_CACHEINDEX_SHIFT=12 \
L2_CACHEWAY_SHIFT=4 \
L2_CACHEWAY_COUNT=12 \
L2_CACHELINE_SHIFT=6 \
PAGE_GRANULE_SHIFT=14 \
PAGE_SIZE=16384 \
WITH_EL3=1 \
WITH_MCC_AS_RAM=1
#16k-algined linker pages
GLOBAL_LDFLAGS += -Wl,-segalign,0x4000
else ifneq (,$(filter apple-hurricane-zephyr,$(ARM_CPU)))
OPTIONS += \
L1_CACHEINDEX_SHIFT=8 \
L1_CACHEWAY_SHIFT=2 \
L2_CACHE_SIZE=3145728 \
L2_CACHEINDEX_SHIFT=11 \
L2_CACHEWAY_SHIFT=4 \
L2_CACHEWAY_COUNT=12 \
L2_CACHELINE_SHIFT=7 \
PAGE_GRANULE_SHIFT=14 \
PAGE_SIZE=16384 \
WITH_L2_AS_RAM=1
#16k-algined linker pages
GLOBAL_LDFLAGS += -Wl,-segalign,0x4000
endif
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=arm64 ARM_ARCH=$(ARM_ARCH)
GLOBAL_INCLUDES += arch/arm/include
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
# Defaults for stack sizes (stacks laid out from top to bottom as listed)
INTERRUPT_STACK_SIZE ?= 8192
BOOTSTRAP_STACK_SIZE ?= 4096
EXCEPTION_STACK_SIZE ?= 4096
OPTIONS += \
INTERRUPT_STACK_SIZE=$(INTERRUPT_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)/fp.o \
$(LOCAL_DIR)/handlers.o \
$(LOCAL_DIR)/task.o
ifeq ($(WITH_EL3),1)
ALL_OBJS += \
$(LOCAL_DIR)/exceptions_el3.o
else
ALL_OBJS += \
$(LOCAL_DIR)/exceptions_el1.o
endif
LINKER_EXPORTS := $(LOCAL_DIR)/link.exp
+262
View File
@@ -0,0 +1,262 @@
/*
* Copyright (c) 2011-2014 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/arm64/proc_reg.h>
#include <platform/memmap.h>
.text
.align 12
.no_dead_strip _start
.globl _start
_start:
// Relocate, if needed
adrp x0, _start@page
add x0, x0, _start@pageoff
ldr x1, L_TEXT_BASE
#ifdef PLATFORM_START_FUNCTION
/*
* x0 and x1 must be preserved
* 'eq' will be true if no text relocation is required
*/
bl PLATFORM_START_FUNCTION
#endif
cmp x1, x0
b.eq L__continue_start
#if !CPU_APPLE_CYCLONE
mov x2, #(SCTLR_I_ENABLED)
msr SCTLR_ELx, x2
ic iallu
#endif
mov lr, x1
ldr x2, L_TEXT_END
ldr x3, L_TEXT_BASE
sub x2, x2, x3
L__relocate_loop:
ldp x3, x4, [x0], #16
stp x3, x4, [x1], #16
subs x2, x2, #16
b.ne L__relocate_loop
ret
L__continue_start:
// Disable all interrupts
msr DAIFSet, #(DAIFSC_ALL)
// Setup return address (virtual)
adrp lr, __main@page
add lr, lr, __main@pageoff
// Set up exception vectors
adrp x10, _exception_vector_base@page
add x10, x10, _exception_vector_base@pageoff
msr VBAR_ELx, x10
// bzero stacks region
ldr x10, L_STACKS_BASE
ldr x11, L_STACKS_SIZE
add x11, x11, x10
mov x12, #0
L__stacks_zero_loop:
stp x12, x12, [x10], #16
cmp x10, x11
b.ne L__stacks_zero_loop
// bzero page tables region
ldr x10, L_PAGE_TABLES_BASE
ldr x11, L_PAGE_TABLES_SIZE
add x11, x11, x10
mov x12, #0
L__tables_zero_loop:
stp x12, x12, [x10], #16
cmp x10, x11
b.ne L__tables_zero_loop
// Set up stack pointers
ldr x10, L_STACKS_BASE
// exception stack goes at very bottom
add x10, x10, #(EXCEPTION_STACK_SIZE)
mov sp, x10 // set SPx to exception stack
// bootstrap stack above exception stack
msr SPSel, #0 // switch to SP0
add x10, x10, #(BOOTSTRAP_STACK_SIZE)
mov sp, x10 // set SP0 to bootstrap stack
// Save interrupt stack top, to be stored after bss is cleared
// interrupt stack goes at top so that it can share with bootstrap
// stack after bootstrap task exits
add x20, x10, #(INTERRUPT_STACK_SIZE)
// SecureROM: relocate data to SRAM
#if APPLICATION_SECUREROM
ldr x10, L_DATA_RO_START
mov x11, #(PAGE_SIZE - 1)
add x10, x10, x11
bic x10, x10, x11
ldr x11, L_DATA_BASE
cmp x10, x11
b.eq L__do_bss
ldr x12, L_DATA_END
L__relocate_data_loop:
ldp x13, x14, [x10], #16
stp x13, x14, [x11], #16
cmp x11, x12
b.ne L__relocate_data_loop
#endif // APPLICATION_SECUREROM
// Clear the bss section
// We requested all the sections to be aligned by 64.
// Section length should be 4 byte aligned.
L__do_bss:
ldr x10, L_BSS_START
ldr x11, L_BSS_END
mov x12, #15
bic x12, x11, x12
mov x13, #0
L__bss_loop_stp:
stp x13, x13, [x10], #16
cmp x10, x12
b.ne L__bss_loop_stp
cmp x11, x12
b.eq L__bss_done
L__bss_loop_word:
str w13, [x10], #4
cmp x10, x11
b.lt L__bss_loop_word
L__bss_done:
// Store interrupt stack top
adrp x11, _interrupt_stack_top@page
add x11, x11, _interrupt_stack_top@pageoff
str x20, [x11]
#if defined(HEAP_GUARD) && (HEAP_GUARD != SRAM_END)
// Clear the heap guard page, which will never be mapped
mov x13, #0
ldr x10, L_HEAP_GUARD
mov x11, #(PAGE_SIZE)
add x11, x10, x11
L__loop_heap_guard:
stp x13, x13, [x10], #16
stp x13, x13, [x10], #16
stp x13, x13, [x10], #16
stp x13, x13, [x10], #16
cmp x10, x11
b.ne L__loop_heap_guard
#endif
#ifdef BOOT_TRAMPOLINE_BASE
// copy the trampoline into a non-writeable page
ldr x3, L_boot_trampoline_start
ldr x4, L_boot_trampoline_end
ldr x5, L_boot_trampoline_dst
1:
ldp x6, x7, [x3], #16
stp x6, x7, [x5], #16
cmp x3, x4
b.lo 1b
#endif
// Branch to main
ret
.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:
.org 0x300
.globl _build_banner_string
_build_banner_string:
.8byte L__build_banner_string
.balign 8
.globl _build_style_string
_build_style_string:
.8byte L__build_style_string
.balign 8
.globl _build_tag_string
_build_tag_string:
.8byte _build_tag_string_contents
.balign 8
// Linked start and end addresses of the text
L_TEXT_BASE:
.8byte (TEXT_BASE)
L_TEXT_END:
.8byte section$start$__DATA$__zerofill
L_TEXT_SIZE:
.8byte segment$end$__TEXT - segment$start$__TEXT
// start address of the data in the read only text */
L_DATA_RO_START:
.8byte segment$end$__TEXT
// Linked start and end addresses of the data
L_DATA_BASE:
.8byte segment$start$__DATA
L_DATA_END:
.8byte section$start$__DATA$__zerofill
// Linked start and end addresses of the zero-filled range
L_BSS_START:
.8byte section$start$__DATA$__zerofill
L_BSS_END:
.8byte segment$end$__DATA
L_STACKS_BASE:
.8byte (STACKS_BASE)
L_STACKS_SIZE:
.8byte (STACKS_SIZE)
L_PAGE_TABLES_BASE:
.8byte (PAGE_TABLES_BASE)
L_PAGE_TABLES_SIZE:
.8byte (PAGE_TABLES_SIZE)
#if defined(HEAP_GUARD) && (HEAP_GUARD != SRAM_END)
L_HEAP_GUARD:
.8byte (HEAP_GUARD)
#endif
#ifdef BOOT_TRAMPOLINE_BASE
L_boot_trampoline_start:
.8byte _boot_handoff_trampoline
L_boot_trampoline_end:
.8byte _boot_handoff_trampoline_end
L_boot_trampoline_dst:
.8byte BOOT_TRAMPOLINE_BASE
#endif
.data
.globl _interrupt_stack_top
_interrupt_stack_top:
.space 8
+52
View File
@@ -0,0 +1,52 @@
/*
* 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 < 29; i++)
t->arch.regs[i] = 0;
/* set the default starting point to be arch_task_trampoline */
t->arch.lr = (uintptr_t)&arch_task_trampoline;
t->arch.sp = (uintptr_t)t->stack_base + t->stack_len;
t->arch.fp = 0;
return 0;
}
+56
View File
@@ -0,0 +1,56 @@
# Copyright (C) 2014 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.
#
CC := $(shell xcodebuild -sdk macosx.internal -find clang)
GCOV := $(shell xcodebuild -sdk macosx.internal -find gcov)
TEST_DIR := host_tests
INCDIRS := . \
include \
../arm/include \
../../include
CFLAGS := -arch x86_64 \
-std=c11 \
-g -Wall -Werror -O \
$(addprefix -I,$(INCDIRS)) \
-DARCH_ARMv8 -DTEST
TESTS := mmu_test
TEST_PASSES := $(patsubst %,$(TEST_DIR)/%.pass,$(TESTS))
.PHONY: all
all: host-tests
.PHONY: host-tests
host-tests: $(TEST_PASSES)
.PHONY: clean
clean:
rm -rf $(TEST_DIR)
rm -f *.gcno *.gcda
$(TEST_DIR)/mmu_test.pass: $(TEST_DIR)/mmu_test
@echo "Test running $(notdir $<)"
@rm -f mmu_test.gcda mmu.gcda
@$< 2>&1 1>$(TEST_DIR)/mmu_test.out || \
{ cat $(TEST_DIR)/mmu_test.out; false; }
@echo "Test passed $(notdir $<)"
@$(GCOV) -a mmu.c
@mv -f mmu.c.gcov $(TEST_DIR)
@grep '#####' $(TEST_DIR)/mmu.c.gcov || true
@touch $@
$(TEST_DIR)/mmu_test: mmu_test.c mmu.c
@echo "Build $(notdir $@)"
@mkdir -p $(dir $@)
@$(CC) -o $@ $^ $(CFLAGS) --coverage
+30
View File
@@ -0,0 +1,30 @@
# Copyright (C) 2014 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)
TEST_NAME := arm64-mmu
TEST_OBJS := \
$(LOCAL_DIR)/mmu.o \
TEST_SUPPORT_OBJS := \
$(LOCAL_DIR)/mmu_test.o
TEST_CFLAGS := \
-DCPU_CACHELINE_SIZE=64 \
-DARCH_ARMv8=1 \
-DTEST=1 \
-Iarch/arm64/include/ \
-Iarch/arm/include
TEST_INCLUDES := \
arch/arm64/include/ \
arch/arm/include
+147
View File
@@ -0,0 +1,147 @@
/*
* 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.
*/
#include <arch.h>
#include <debug.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/timer.h>
extern void arm_write_cntp_ctl(uint64_t);
extern uint64_t arm_read_cntp_ctl();
extern void arm_write_cntp_tval(uint64_t);
extern uint64_t arm_read_cntpct();
static void timer_deadline(void *arg);
static void (* timer_deadline_func)(void);
#define DECR_MAX_COUNT (INT32_MAX)
int timer_init(uint32_t timer)
{
uint64_t val;
val = (0<<0) | (1<<1);
arm_write_cntp_ctl(val);
return 0;
}
void timer_stop_all(void)
{
uint64_t val;
val = (0<<0) | (1<<1);
arm_write_cntp_ctl(val);
}
void timer_deadline_enter(uint64_t deadline, void (* func)(void))
{
uint64_t ticks;
uint64_t decr;
uint64_t val;
timer_deadline_func = func;
if (func) {
/* convert absolute deadline to relative time */
ticks = timer_get_ticks();
if (deadline < ticks) {
// printf(" %llu too soon (it is now %llu)\n", deadline, ticks);
deadline = 0;
} else {
deadline -= ticks;
}
/* clamp the deadline to our maximum */
decr = (deadline >= DECR_MAX_COUNT) ? DECR_MAX_COUNT : deadline;
// printf(" using decrementer count %u\n", decr);
/*
* Reset the decrementer by programming the max count, clearing
* any pending interrupt status, then programming the desired count.
* Note the timer's value is a signed 32 bit number
*/
arm_write_cntp_tval(DECR_MAX_COUNT);
val = (1<<0) | (0<<1);
arm_write_cntp_ctl(val);
arm_write_cntp_tval(decr);
} else {
/* no deadline, disable the decrementer */
val = (0<<0) | (1<<1);
arm_write_cntp_ctl(val);
}
}
void arm_fiq()
{
uint64_t val;
_irq_enter_critical_section();
val = arm_read_cntp_ctl();
if (val & (1 << 2)) {
/* acknowledge the interrupt and disable the timer */
val = (0<<0) | (1<<1);
arm_write_cntp_ctl(val);
/* if we have a callback, invoke it now */
if (timer_deadline_func)
timer_deadline_func();
}
_irq_exit_critical_section();
}
#ifdef OSC_FREQ
utime_t timer_ticks_to_usecs(uint64_t ticks)
{
#if (OSC_FREQ % 1000000) == 0
return ticks / (OSC_FREQ / 1000000);
#else
#error "The code below has overflow issues. Make sure you really want to use it"
return (ticks * 1000 * 1000) / OSC_FREQ;
#endif
}
uint64_t timer_usecs_to_ticks(utime_t usecs)
{
#if (OSC_FREQ % 1000000) == 0
return usecs * (OSC_FREQ / 1000000);
#else
#error "The code below has overflow issues. Make sure you really want to use it"
uint64_t timer_scale = ((uint64_t)(OSC_FREQ) << 20) / (1000 * 1000);
return (ticks * timer_scale) >> 20;
#endif
}
uint32_t timer_get_tick_rate(void)
{
return OSC_FREQ;
}
#endif
uint64_t timer_get_ticks(void)
{
return (arm_read_cntpct());
}
void arm_no_wfe_spin(uint32_t usecs)
{
uint64_t delta_time = (uint64_t)usecs * (OSC_FREQ / 1000000);
uint64_t start_time;
start_time = timer_get_ticks();
while (true) {
if ((timer_get_ticks() - start_time) > delta_time)
break;
}
}