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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
//----------------------------------------------------------------
// Copyright (c) 2005-2018 Arm Limited (or its affiliates). All rights reserved.
// Use, modification and redistribution of this file is subject to your possession of a
// valid End User License Agreement for the Arm Product of which these examples are part of
// and your compliance with all applicable terms and conditions of such licence agreement.
//
// Cortex-A8MP example - Startup Code
//----------------------------------------------------------------
.text
//----------------------------------------------------------------
// GIC. Generic Interrupt Controller Architecture Specification
//----------------------------------------------------------------
// CPU Interface offset from base of private peripheral space --> 0x0100
// Interrupt Distributor offset from base of private peripheral space --> 0x1000
// Typical calls to enable interrupt ID X:
// enableIntID(X) <-- Enable that ID
// setIntPriority(X, 0) <-- Set the priority of X to 0 (the max priority)
// setPriorityMask(0x1F) <-- Set CPU's priority mask to 0x1F (the lowest priority)
// enableGIC() <-- Enable the GIC (global)
// enableGICProcessorInterface() <-- Enable the CPU interface (local to the CPU)
// void enableGIC(void)
// Global enable of the Interrupt Distributor
.global enableGIC
.type enableGIC,function
enableGIC:
// Get base address of private peripheral space
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x1000 // Add the GIC offset
LDR r1, [r0] // Read the GIC Enable Register (ICDDCR)
ORR r1, r1, #0x01 // Set bit 0, the enable bit
STR r1, [r0] // Write the GIC Enable Register (ICDDCR)
BX lr
// ------------------------------------------------------------
.global disableGIC
.type disableGIC,function
// void disableGIC(void)
// Global disable of the Interrupt Distributor
disableGIC:
// Get base address of private peripheral space
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x1000 // Add the GIC offset
LDR r1, [r0] // Read the GIC Enable Register (ICDDCR)
BIC r1, r1, #0x01 // Clear bit 0, the enable bit
STR r1, [r0] // Write the GIC Enable Register (ICDDCR)
BX lr
// ------------------------------------------------------------
.global enableIntID
.type enableIntID,function
// void enableIntID(unsigned int ID)
// Enables the interrupt source number ID
enableIntID:
// Get base address of private peripheral space
MOV r1, r0 // Back up passed in ID value
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
// Each interrupt source has an enable bit in the GIC. These
// are grouped into registers, with 32 sources per register
// First, we need to identify which 32-bit block the interrupt lives in
MOV r2, r1 // Make working copy of ID in r2
MOV r2, r2, LSR #5 // LSR by 5 places, affective divide by 32
// r2 now contains the 32-bit block this ID lives in
MOV r2, r2, LSL #2 // Now multiply by 4, to convert offset into an address offset (four bytes per reg)
// Now work out which bit within the 32-bit block the ID is
AND r1, r1, #0x1F // Mask off to give offset within 32-bit block
MOV r3, #1 // Move enable value into r3
MOV r3, r3, LSL r1 // Shift it left to position of ID
ADD r2, r2, #0x1100 // Add the base offset of the Enable Set registers to the offset for the ID
STR r3, [r0, r2] // Store out (ICDISER)
BX lr
// ------------------------------------------------------------
.global disableIntID
.type disableIntID,function
// void disableIntID(unsigned int ID)
// Disables the interrupt source number ID
disableIntID:
// Get base address of private peripheral space
MOV r1, r0 // Back up passed in ID value
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
// First, we need to identify which 32-bit block the interrupt lives in
MOV r2, r1 // Make working copy of ID in r2
MOV r2, r2, LSR #5 // LSR by 5 places, affective divide by 32
// r2 now contains the 32-bit block this ID lives in
MOV r2, r2, LSL #2 // Now multiply by 4, to convert offset into an address offset (four bytes per reg)
// Now work out which bit within the 32-bit block the ID is
AND r1, r1, #0x1F // Mask off to give offset within 32-bit block
MOV r3, #1 // Move enable value into r3
MOV r3, r3, LSL r1 // Shift it left to position of ID in 32-bit block
ADD r2, r2, #0x1180 // Add the base offset of the Enable Clear registers to the offset for the ID
STR r3, [r0, r2] // Store out (ICDICER)
BX lr
// ------------------------------------------------------------
.global setIntPriority
.type setIntPriority,function
// void setIntPriority(unsigned int ID, unsigned int priority)
// Sets the priority of the specified ID
// r0 = ID
// r1 = priority
setIntPriority:
// Get base address of private peripheral space
MOV r2, r0 // Back up passed in ID value
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
// r0 = base addr
// r1 = priority
// r2 = ID
// Make sure that priority value is only 5 bits, and convert to expected format
AND r1, r1, #0x1F
MOV r1, r1, LSL #3
// Find which register this ID lives in
BIC r3, r2, #0x03 // Make a copy of the ID, clearing off the bottom two bits
// There are four IDs per reg, by clearing the bottom two bits we get an address offset
ADD r3, r3, #0x1400 // Now add the offset of the Priority Level registers from the base of the private peripheral space
ADD r0, r0, r3 // Now add in the base address of the private peripheral space, giving us the absolute address
// Now work out which ID in the register it is
AND r2, r2, #0x03 // Clear all but the bottom two bits, leaves which ID in the reg it is (which byte)
MOV r2, r2, LSL #3 // Multiply by 8, this gives a bit offset
// Read -> Modify -> Write
MOV r12, #0xFF // 8 bit field mask
MOV r12, r12, LSL r2 // Move mask into correct bit position
MOV r1, r1, LSL r2 // Also, move passed in priority value into correct bit position
LDR r3, [r0] // Read current value of the Priority Level register (ICDIPR)
BIC r3, r3, r12 // Clear appropriate field
ORR r3, r3, r1 // Now OR in the priority value
STR r3, [r0] // And store it back again (ICDIPR)
BX lr
// ------------------------------------------------------------
.global enableGICProcessorInterface
.type enableGICProcessorInterface,function
// void enableGICProcessorInterface(void)
// Enables the processor interface
// Must be done on each core separately
enableGICProcessorInterface:
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x2000
LDR r1, [r0, #0x0] // Read the Processor Interface Control register (ICCICR/ICPICR)
ORR r1, r1, #0x03 // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts
BIC r1, r1, #0x08 // Bit 3: Ensure Group 0 interrupts are signalled using IRQ, not FIQ
STR r1, [r0, #0x0] // Write the Processor Interface Control register (ICCICR/ICPICR)
BX lr
// ------------------------------------------------------------
.global disableGICProcessorInterface
.type disableGICProcessorInterface,function
// void disableGICProcessorInterface(void)
// Disables the processor interface
// Must be done on each core separately
disableGICProcessorInterface:
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x2000
LDR r1, [r0, #0x0] // Read the Processor Interface Control register (ICCICR/ICPICR)
BIC r1, r1, #0x03 // Bit 0: Enables secure interrupts, Bit 1: Enables Non-Secure interrupts
STR r1, [r0, #0x0] // Write the Processor Interface Control register (ICCICR/ICPICR)
BX lr
// ------------------------------------------------------------
.global setPriorityMask
.type setPriorityMask,function
// void setPriorityMask(unsigned int priority)
// Sets the Priority mask register for the CPU run on
// The reset value masks ALL interrupts!
setPriorityMask:
// Get base address of private peripheral space
MRC p15, 4, r1, c15, c0, 0 // Read periph base address
ADD r1, r1, #0x2000
STR r0, [r1, #0x4] // Write the Priority Mask register (ICCPMR/ICCIPMR)
BX lr
// ------------------------------------------------------------
.global setBinaryPoint
.type setBinaryPoint,function
// void setBinaryPoint(unsigned int priority)
// Sets the Binary Point Register for the CPU run on
setBinaryPoint:
// Get base address of private peripheral space
MRC p15, 4, r1, c15, c0, 0 // Read periph base address
ADD r1, r1, #0x2000
STR r0, [r1, #0x8] // Write the Binary register (ICCBPR/ICCBPR)
BX lr
// ------------------------------------------------------------
.global readIntAck
.type readIntAck,function
// unsigned int readIntAck(void)
// Returns the value of the Interrupt Acknowledge Register
readIntAck:
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x2000
LDR r0, [r0, #0xC] // Read the Interrupt Acknowledge Register (ICCIAR)
BX lr
// ------------------------------------------------------------
.global writeEOI
.type writeEOI,function
// void writeEOI(unsigned int ID)
// Writes ID to the End Of Interrupt register
writeEOI:
// Get base address of private peripheral space
MRC p15, 4, r1, c15, c0, 0 // Read periph base address
ADD r1, r1, #0x2000
STR r0, [r1, #0x10] // Write ID to the End of Interrupt register (ICCEOIR)
BX lr
//----------------------------------------------------------------
// SGI
//----------------------------------------------------------------
.global sendSGI
.type sendSGI,function
// void sendSGI(unsigned int ID, unsigned int target_list, unsigned int filter_list)//
// Send a software generate interrupt
sendSGI:
AND r3, r0, #0x0F // Mask off unused bits of ID, and move to r3
AND r1, r1, #0x0F // Mask off unused bits of target_filter
AND r2, r2, #0x0F // Mask off unused bits of filter_list
ORR r3, r3, r1, LSL #16 // Combine ID and target_filter
ORR r3, r3, r2, LSL #24 // and now the filter list
// Get the address of the GIC
MRC p15, 4, r0, c15, c0, 0 // Read periph base address
ADD r0, r0, #0x1F00 // Add offset of the sgi_trigger reg
STR r3, [r0] // Write to the Software Generated Interrupt Register (ICDSGIR)
BX lr
//----------------------------------------------------------------
// End of MP_GIC.s
//----------------------------------------------------------------
|