summaryrefslogtreecommitdiff
path: root/libcpu/aarch64/cortex-a/entry_point.S
blob: 2228677f1cfa15038308c906dc039e93f78f97cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Date           Author       Notes
 * 2020-01-15     bigmagic     the first version
 * 2020-08-10     SummerGift   support clang compiler
 * 2021-11-04     GuEe-GUI     set sp with SP_ELx
 * 2021-12-28     GuEe-GUI     add smp support
 */

#include "rtconfig.h"
.section ".text.entrypoint","ax"

#define SECONDARY_STACK_SIZE 4096

.globl _start
.globl secondary_cpu_start
_start:
    mrs     x1, mpidr_el1
    and     x1, x1, #0xff
    cbnz    x1, cpu_idle            /* If cpu id > 0, stop slave cores */

secondary_cpu_start:
#ifdef RT_USING_SMP
    /* Read cpu mpidr_el1 */
    mrs     x1, mpidr_el1

    /* Read cpu id */
    ldr     x0, =rt_cpu_mpidr_early /* BSP must be defined `rt_cpu_mpidr_early' table in smp */
    mov     x2, #0

cpu_id_confirm:
    add     x2, x2, #1              /* Next cpu id inc */
    ldr     x3, [x0], #8
    cmp     x3, #0
    beq     cpu_idle                /* Mean that `rt_cpu_mpidr_early' table is end */
    cmp     x3, x1
    bne     cpu_id_confirm

    /* Get cpu id success */
    sub     x0, x2, #1
    msr     tpidr_el1, x0           /* Save cpu id global */
    cbz     x0, cpu_setup           /* Only go to cpu_setup when cpu id = 0 */

    /* Set current cpu's stack top */
    sub     x0, x0, #1
    mov     x1, #SECONDARY_STACK_SIZE
    adr     x2, .secondary_cpu_stack_top
    msub    x1, x0, x1, x2

    b       cpu_check_el
#else
    msr     tpidr_el1, xzr
    b       cpu_setup
#endif /* RT_USING_SMP */

cpu_idle:
    wfe
    b       cpu_idle

cpu_setup:
    ldr     x1, =_start

cpu_check_el:
    mrs     x0, CurrentEL           /* CurrentEL Register. bit 2, 3. Others reserved */
    and     x0, x0, #12             /* Clear reserved bits */

    /* Running at EL3? */
    cmp     x0, #12                 /* EL3 value is 0b1100 */
    bne     cpu_not_in_el3

    /* Should never be executed, just for completeness. (EL3) */
    mov     x2, #(1 << 0)           /* EL0 and EL1 are in Non-Secure state */
    orr     x2, x2, #(1 << 4)       /* RES1 */
    orr     x2, x2, #(1 << 5)       /* RES1 */
    orr     x2, x2, #(1 << 7)       /* SMC instructions are undefined at EL1 and above */
    orr     x2, x2, #(1 << 8)       /* HVC instructions are enabled at EL1 and above */
    orr     x2, x2, #(1 << 10)      /* The next lower level is AArch64 */
    msr     scr_el3, x2

    /* Change execution level to EL2 */
    mov     x2, #0x3c9
    msr     spsr_el3, x2            /* 0b1111001001 */
    adr     x2, cpu_not_in_el3
    msr     elr_el3, x2
    eret                            /* Exception Return: from EL3, continue from cpu_not_in_el3 */

cpu_not_in_el3:                     /* Running at EL2 or EL1 */
    cmp     x0, #4                  /* EL1 = 0100  */
    beq     cpu_in_el1              /* Halt this core if running in El1 */

cpu_in_el2:
    /* Enable CNTP for EL1 */
    mrs     x0, cnthctl_el2         /* Counter-timer Hypervisor Control register */
    orr     x0, x0, #3
    msr     cnthctl_el2, x0
    msr     cntvoff_el2, xzr

    mov     x0, #(1 << 31)          /* Enable AArch64 in EL1 */
    orr     x0, x0, #(1 << 1)       /* SWIO hardwired on Pi3 */
    msr     hcr_el2, x0

    /* Change execution level to EL1 */
    mov     x2, #0x3c4
    msr     spsr_el2, x2            /* 0b1111000100 */
    adr     x2, cpu_in_el1
    msr     elr_el2, x2
    eret

cpu_in_el1:
    msr     spsel, #1
    mov     sp, x1                  /* Set sp in el1 */

    /* Avoid trap from SIMD or float point instruction */
    mov     x1, #0x00300000         /* Don't trap any SIMD/FP instructions in both EL0 and EL1 */
    msr     cpacr_el1, x1

    mrs     x1, sctlr_el1
    orr     x1, x1, #(1 << 12)      /* Enable Instruction */
    bic     x1, x1, #(3 << 3)       /* Disable SP Alignment check */
    bic     x1, x1, #(1 << 1)       /* Disable Alignment check */
    msr     sctlr_el1, x1

#ifdef RT_USING_SMP
    ldr     x1, =_start
    cmp     sp, x1
    bne     secondary_cpu_c_start
#endif /* RT_USING_SMP */

    ldr     x0, =__bss_start
    ldr     x1, =__bss_end
    sub     x2, x1, x0
    mov     x3, x1
    cmp     x2, #7
    bls     clean_bss_check

clean_bss_loop_quad:
    str     xzr, [x0], #8
    sub     x2, x3, x0
    cmp     x2, #7
    bhi     clean_bss_loop_quad
    cmp     x1, x0
    bls     jump_to_entry

clean_bss_loop_byte:
    str     xzr, [x0], #1

clean_bss_check:
    cmp     x1, x0
    bhi     clean_bss_loop_byte

jump_to_entry:
    b       rtthread_startup
    b       cpu_idle                /* For failsafe, halt this core too */

#ifdef RT_USING_SMP
.align 12
.secondary_cpu_stack:
.space (SECONDARY_STACK_SIZE * (RT_CPUS_NR - 1))
.secondary_cpu_stack_top:
#endif