aboutsummaryrefslogtreecommitdiff
path: root/bdk/exception_handlers.S
blob: 97d1ec67927fa5e19f6c30322849bb3383756843 (plain) (blame)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
 * Copyright (c) 2019 CTCaer
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Armv7tdmi Status register.
 *
 * bit0: Mode 0.
 * bit1: Mode 1.
 * bit2: Mode 2.
 * bit3: Mode 3.
 * bit4: Mode 4.
 * bit5: Thumb state.
 * bit6: FIQ disable.
 * bit7: IRQ disable.
 * bit8-27: Reserved.
 * bit28: Overflow condition.
 * bit29: Carry/Borrow/Extend condition.
 * bit30: Zero condition.
 * bit31: Negative/Less than condition.
 *
 * M[4:0] | Mode | Visible Thumb-state registers             | Visible ARM-state registers
 * 10000  | USER | r0–r7, SP,     LR,     PC, CPSR           | r0–r14,                   PC, CPSR
 * 10001  | FIQ  | r0–r7, SP_fiq, LR_fiq, PC, CPSR, SPSR_fiq | r0–r7,  r8_fiq–r14_fiq,   PC, CPSR, SPSR_fiq
 * 10010  | IRQ  | r0–r7, SP_irq, LR_irq, PC, CPSR, SPSR_irq | r0–r12, r13_irq, r14_irq, PC, CPSR, SPSR_irq
 * 10011  | SVC  | r0–r7, SP_svc, LR_svc, PC, CPSR, SPSR_svc | r0–r12, r13_svc, r14_svc, PC, CPSR, SPSR_svc
 * 10111  | ABRT | r0–r7, SP_abt, LR_abt, PC, CPSR, SPSR_abt | r0–r12, r13_abt, r14_abt, PC, CPSR, SPSR_abt
 * 11011  | UNDF | r0–r7, SP_und, LR_und, PC, CPSR, SPSR_und | r0–r12, r13_und, r14_und, PC, CPSR, SPSR_und
 * 11111  | SYS  | r0–r7, SP,     LR,     PC, CPSR           | r0–r14,                   PC, CPSR
 */

#define EXCP_EN_ADDR   0x4003FFFC
#define EXCP_TYPE_ADDR 0x4003FFF8
#define EXCP_LR_ADDR   0x4003FFF4

#define EXCP_VEC_BASE  0x6000F000
#define EVP_COP_RESET_VECTOR          0x200
#define EVP_COP_UNDEF_VECTOR          0x204
#define EVP_COP_SWI_VECTOR            0x208
#define EVP_COP_PREFETCH_ABORT_VECTOR 0x20C
#define EVP_COP_DATA_ABORT_VECTOR     0x210
#define EVP_COP_RSVD_VECTOR           0x214
#define EVP_COP_IRQ_VECTOR            0x218
#define EVP_COP_FIQ_VECTOR            0x21C

#define MODE_USR  0x10
#define MODE_FIQ  0x11
#define MODE_IRQ  0x12
#define MODE_SVC  0x13
#define MODE_ABT  0x17
#define MODE_UDF  0x1B
#define MODE_SYS  0x1F
#define MODE_MASK 0x1F

#define FIQ 0x40
#define IRQ 0x80

.section .text._irq_setup
.arm

.extern ipl_main
.type ipl_main, %function

.extern svc_handler
.type svc_handler, %function

.extern irq_handler
.type irq_handler, %function

.extern fiq_setup
.type fiq_setup, %function

.extern fiq_handler
.type fiq_handler, %function

.globl _irq_setup
.type _irq_setup, %function
_irq_setup:
	MRS R0, CPSR
	BIC R0, R0, #MODE_MASK              /* Clear mode bits */
	ORR R0, R0, #(MODE_SVC | IRQ | FIQ) /* SUPERVISOR mode, IRQ/FIQ disabled */
	MSR CPSR, R0

	/* Setup IRQ stack pointer */
	MSR CPSR, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
	LDR SP, =0x40040000

	/* Setup SYS stack pointer */
	MSR CPSR, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
	LDR SP, =0x4003FF00               /* Will be changed later to DRAM */

	MOV LR, PC
	BL setup_vectors
	/*BL fiq_setup*/

	/* Enable interrupts */
	BL irq_enable_cpu_irq_exceptions

	B ipl_main
	B .

_reset:
	LDR R0, =EXCP_EN_ADDR
	LDR R1, =0x30505645 /* EVP0 */
	STR R1, [R0]        /* EVP0 in EXCP_EN_ADDR */
	LDR R0, =EXCP_LR_ADDR
	MOV R1, LR
	STR R1, [R0]        /* Save LR in EXCP_LR_ADDR */
	LDR R0, =__bss_start
	EOR R1, R1, R1
	LDR R2, =__bss_end
	SUB R2, R2, R0
	BL memset
	B _irq_setup

_reset_handler:
	LDR R0, =EXCP_TYPE_ADDR
	LDR R1, =0x545352   /* RST */
	STR R1, [R0]        /* RST in EXCP_TYPE_ADDR */
	B _reset

_undefined_handler:
	LDR R0, =EXCP_TYPE_ADDR
	LDR R1, =0x464455   /* UDF */
	STR R1, [R0]        /* UDF in EXCP_TYPE_ADDR */
	B _reset

_prefetch_abort_handler:
	LDR R0, =EXCP_TYPE_ADDR
	LDR R1, =0x54424150 /* PABT */
	STR R1, [R0]        /* PABT in EXCP_TYPE_ADDR */
	B _reset

_data_abort_handler:
	LDR R0, =EXCP_TYPE_ADDR
	LDR R1, =0x54424144 /* DABT */
	STR R1, [R0]        /* DABT in EXCP_TYPE_ADDR */
	B _reset

.globl irq_enable_cpu_irq_exceptions
.type irq_enable_cpu_irq_exceptions, %function
irq_enable_cpu_irq_exceptions:
	MRS R12, CPSR
	BIC R12, R12, #(IRQ | FIQ) /* IRQ/FIQ enabled */
	MSR CPSR, R12
	BX LR

.globl irq_disable_cpu_irq_exceptions
.type irq_disable_cpu_irq_exceptions, %function
irq_disable_cpu_irq_exceptions:
	MRS R12, CPSR
	ORR R12, R12, #(IRQ | FIQ) /* IRQ/FIQ disabled */
	MSR CPSR, R12
	BX LR

_irq_handler:
	MOV R13, R0    /* Save R0 in R13_IRQ */
	SUB R0, LR, #4 /* Put return address in R0_SYS */
	MOV LR, R1     /* Save R1 in R14_IRQ (LR) */
	MRS R1, SPSR   /* Put the SPSR in R1_SYS */

	MSR CPSR_c, #(MODE_SYS | IRQ)  /* SYSTEM mode, IRQ disabled */
	STMFD SP!, {R0, R1}            /* SPSR and PC */
	STMFD SP!, {R2-R3, R12, LR}    /* AAPCS-clobbered registers */
	MOV R0, SP                     /* Make SP_SYS visible to IRQ mode */
	SUB SP, SP, #8                 /* Make room for stacking R0 and R1 */

	MSR CPSR_c, #(MODE_IRQ | IRQ) /* IRQ mode, IRQ disabled */
	STMFD R0!, {R13, R14}         /* Finish saving the context (R0, R1) */

	MSR CPSR_c, #(MODE_SYS | IRQ) /* SYSTEM mode, IRQ disabled */
	LDR R12, =irq_handler
	MOV LR, PC                    /* Copy the return address to link register */
	BX R12                        /* Call the C IRQ handler (ARM/THUMB) */

	MSR CPSR_c, #(MODE_SYS | IRQ | FIQ) /* SYSTEM mode, IRQ/FIQ disabled */
	MOV R0, SP                          /* Make SP_SYS visible to IRQ mode */
	ADD SP, SP, #32                     /* Fake unstacking 8 registers from SP_SYS */

	MSR CPSR_c, #(MODE_IRQ | IRQ | FIQ) /* IRQ mode, IRQ/FIQ disabled */
	MOV SP, R0                          /* Copy SP_SYS to SP_IRQ */
	LDR R0, [SP, #28]                   /* Load the saved SPSR from the stack */
	MSR SPSR_cxsf, R0                   /* Copy it into SPSR_IRQ */

	LDMFD SP, {R0-R3, R12, LR}^ /* Unstack all saved USER/SYSTEM registers */
	NOP                         /* Cant access barked registers immediately */
	LDR LR, [SP, #24]           /* Load return address from the SYS stack */
	MOVS PC, LR                 /* Return restoring CPSR from SPSR */

_fiq_handler:
	BL fiq_handler

setup_vectors:
	/* Setup vectors */
	LDR R0, =EXCP_VEC_BASE

	LDR R1, =_reset_handler
	STR R1, [R0, #EVP_COP_RESET_VECTOR]

	LDR R1, =_undefined_handler
	STR R1, [R0, #EVP_COP_UNDEF_VECTOR]

	LDR R1, =_reset_handler
	STR R1, [R0, #EVP_COP_SWI_VECTOR]

	LDR R1, =_prefetch_abort_handler
	STR R1, [R0, #EVP_COP_PREFETCH_ABORT_VECTOR]

	LDR R1, =_data_abort_handler
	STR R1, [R0, #EVP_COP_DATA_ABORT_VECTOR]

	LDR R1, =_reset_handler
	STR R1, [R0, #EVP_COP_RSVD_VECTOR]

	LDR R1, =_irq_handler
	STR R1, [R0, #EVP_COP_IRQ_VECTOR]

	LDR R1, =_fiq_handler
	STR R1, [R0, #EVP_COP_FIQ_VECTOR]

	BX LR