1 /* 2 * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved. 3 * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #include <assert.h> 9 #include <stdbool.h> 10 11 #include <arch_helpers.h> 12 #include <common/bl_common.h> 13 #include <common/debug.h> 14 #include <bl31/interrupt_mgmt.h> 15 #include <drivers/arm/gic_common.h> 16 #include <drivers/arm/gicv3.h> 17 #include <lib/cassert.h> 18 #include <plat/common/platform.h> 19 20 #ifdef IMAGE_BL31 21 22 /* 23 * The following platform GIC functions are weakly defined. They 24 * provide typical implementations that may be re-used by multiple 25 * platforms but may also be overridden by a platform if required. 26 */ 27 #pragma weak plat_ic_get_pending_interrupt_id 28 #pragma weak plat_ic_get_pending_interrupt_type 29 #pragma weak plat_ic_acknowledge_interrupt 30 #pragma weak plat_ic_get_interrupt_type 31 #pragma weak plat_ic_end_of_interrupt 32 #pragma weak plat_interrupt_type_to_line 33 34 #pragma weak plat_ic_get_running_priority 35 #pragma weak plat_ic_is_spi 36 #pragma weak plat_ic_is_ppi 37 #pragma weak plat_ic_is_sgi 38 #pragma weak plat_ic_get_interrupt_active 39 #pragma weak plat_ic_enable_interrupt 40 #pragma weak plat_ic_disable_interrupt 41 #pragma weak plat_ic_set_interrupt_priority 42 #pragma weak plat_ic_set_interrupt_type 43 #pragma weak plat_ic_raise_el3_sgi 44 #pragma weak plat_ic_raise_ns_sgi 45 #pragma weak plat_ic_raise_s_el1_sgi 46 #pragma weak plat_ic_set_spi_routing 47 #pragma weak plat_ic_set_interrupt_pending 48 #pragma weak plat_ic_clear_interrupt_pending 49 50 /* 51 * This function returns the highest priority pending interrupt at 52 * the Interrupt controller 53 */ 54 uint32_t plat_ic_get_pending_interrupt_id(void) 55 { 56 unsigned int irqnr; 57 58 assert(IS_IN_EL3()); 59 irqnr = gicv3_get_pending_interrupt_id(); 60 return gicv3_is_intr_id_special_identifier(irqnr) ? 61 INTR_ID_UNAVAILABLE : irqnr; 62 } 63 64 /* 65 * This function returns the type of the highest priority pending interrupt 66 * at the Interrupt controller. In the case of GICv3, the Highest Priority 67 * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine 68 * the id of the pending interrupt. The type of interrupt depends upon the 69 * id value as follows. 70 * 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt 71 * 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt. 72 * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt 73 * type. 74 * 4. All other interrupt id's are reported as EL3 interrupt. 75 */ 76 uint32_t plat_ic_get_pending_interrupt_type(void) 77 { 78 unsigned int irqnr; 79 uint32_t type; 80 81 assert(IS_IN_EL3()); 82 irqnr = gicv3_get_pending_interrupt_type(); 83 84 switch (irqnr) { 85 case PENDING_G1S_INTID: 86 type = INTR_TYPE_S_EL1; 87 break; 88 case PENDING_G1NS_INTID: 89 type = INTR_TYPE_NS; 90 break; 91 case GIC_SPURIOUS_INTERRUPT: 92 type = INTR_TYPE_INVAL; 93 break; 94 default: 95 type = INTR_TYPE_EL3; 96 break; 97 } 98 99 return type; 100 } 101 102 /* 103 * This function returns the highest priority pending interrupt at 104 * the Interrupt controller and indicates to the Interrupt controller 105 * that the interrupt processing has started. 106 */ 107 uint32_t plat_ic_acknowledge_interrupt(void) 108 { 109 assert(IS_IN_EL3()); 110 return gicv3_acknowledge_interrupt(); 111 } 112 113 /* 114 * This function returns the type of the interrupt `id`, depending on how 115 * the interrupt has been configured in the interrupt controller. 116 */ 117 uint32_t plat_ic_get_interrupt_type(uint32_t id) 118 { 119 unsigned int group; 120 121 assert(IS_IN_EL3()); 122 group = gicv3_get_interrupt_group(id, plat_my_core_pos()); 123 124 switch (group) { 125 case INTR_GROUP0: 126 return INTR_TYPE_EL3; 127 case INTR_GROUP1S: 128 return INTR_TYPE_S_EL1; 129 case INTR_GROUP1NS: 130 return INTR_TYPE_NS; 131 default: 132 assert(false); /* Unreachable */ 133 return INTR_TYPE_EL3; 134 } 135 } 136 137 /* 138 * This functions is used to indicate to the interrupt controller that 139 * the processing of the interrupt corresponding to the `id` has 140 * finished. 141 */ 142 void plat_ic_end_of_interrupt(uint32_t id) 143 { 144 assert(IS_IN_EL3()); 145 gicv3_end_of_interrupt(id); 146 } 147 148 /* 149 * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. 150 * The interrupt controller knows which pin/line it uses to signal a type of 151 * interrupt. It lets the interrupt management framework determine for a type of 152 * interrupt and security state, which line should be used in the SCR_EL3 to 153 * control its routing to EL3. The interrupt line is represented as the bit 154 * position of the IRQ or FIQ bit in the SCR_EL3. 155 */ 156 uint32_t plat_interrupt_type_to_line(uint32_t type, 157 uint32_t security_state) 158 { 159 assert((type == INTR_TYPE_S_EL1) || 160 (type == INTR_TYPE_EL3) || 161 (type == INTR_TYPE_NS)); 162 163 assert(sec_state_is_valid(security_state)); 164 assert(IS_IN_EL3()); 165 166 switch (type) { 167 case INTR_TYPE_S_EL1: 168 /* 169 * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts 170 * and as FIQ in the NS-EL0/1/2 contexts 171 */ 172 if (security_state == SECURE) 173 return __builtin_ctz(SCR_IRQ_BIT); 174 else 175 return __builtin_ctz(SCR_FIQ_BIT); 176 assert(0); /* Unreachable */ 177 case INTR_TYPE_NS: 178 /* 179 * The Non secure interrupts will be signaled as FIQ in S-EL0/1 180 * contexts and as IRQ in the NS-EL0/1/2 contexts. 181 */ 182 if (security_state == SECURE) 183 return __builtin_ctz(SCR_FIQ_BIT); 184 else 185 return __builtin_ctz(SCR_IRQ_BIT); 186 assert(0); /* Unreachable */ 187 case INTR_TYPE_EL3: 188 /* 189 * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and 190 * NS-EL0/1/2 contexts 191 */ 192 return __builtin_ctz(SCR_FIQ_BIT); 193 default: 194 panic(); 195 } 196 } 197 198 unsigned int plat_ic_get_running_priority(void) 199 { 200 return gicv3_get_running_priority(); 201 } 202 203 int plat_ic_is_spi(unsigned int id) 204 { 205 return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID); 206 } 207 208 int plat_ic_is_ppi(unsigned int id) 209 { 210 return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID); 211 } 212 213 int plat_ic_is_sgi(unsigned int id) 214 { 215 return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); 216 } 217 218 unsigned int plat_ic_get_interrupt_active(unsigned int id) 219 { 220 return gicv3_get_interrupt_active(id, plat_my_core_pos()); 221 } 222 223 void plat_ic_enable_interrupt(unsigned int id) 224 { 225 gicv3_enable_interrupt(id, plat_my_core_pos()); 226 } 227 228 void plat_ic_disable_interrupt(unsigned int id) 229 { 230 gicv3_disable_interrupt(id, plat_my_core_pos()); 231 } 232 233 void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority) 234 { 235 gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority); 236 } 237 238 int plat_ic_has_interrupt_type(unsigned int type) 239 { 240 assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) || 241 (type == INTR_TYPE_NS)); 242 return 1; 243 } 244 245 void plat_ic_set_interrupt_type(unsigned int id, unsigned int type) 246 { 247 unsigned int group; 248 249 switch (type) { 250 case INTR_TYPE_EL3: 251 group = INTR_GROUP0; 252 break; 253 case INTR_TYPE_S_EL1: 254 group = INTR_GROUP1S; 255 break; 256 case INTR_TYPE_NS: 257 group = INTR_GROUP1NS; 258 break; 259 default: 260 assert(false); /* Unreachable */ 261 group = INTR_GROUP0; 262 break; 263 } 264 265 gicv3_set_interrupt_group(id, plat_my_core_pos(), group); 266 } 267 268 void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target) 269 { 270 /* Target must be a valid MPIDR in the system */ 271 assert(plat_core_pos_by_mpidr(target) >= 0); 272 273 /* Verify that this is a secure EL3 SGI */ 274 assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) == 275 INTR_TYPE_EL3); 276 277 gicv3_raise_sgi((unsigned int)sgi_num, GICV3_G0, target); 278 } 279 280 void plat_ic_raise_ns_sgi(int sgi_num, u_register_t target) 281 { 282 /* Target must be a valid MPIDR in the system */ 283 assert(plat_core_pos_by_mpidr(target) >= 0); 284 285 /* Verify that this is a non-secure SGI */ 286 assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) == 287 INTR_TYPE_NS); 288 289 gicv3_raise_sgi((unsigned int)sgi_num, GICV3_G1NS, target); 290 } 291 292 void plat_ic_raise_s_el1_sgi(int sgi_num, u_register_t target) 293 { 294 /* Target must be a valid MPIDR in the system */ 295 assert(plat_core_pos_by_mpidr(target) >= 0); 296 297 /* Verify that this is a secure EL1 SGI */ 298 assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) == 299 INTR_TYPE_S_EL1); 300 301 gicv3_raise_sgi((unsigned int)sgi_num, GICV3_G1S, target); 302 } 303 304 void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, 305 u_register_t mpidr) 306 { 307 unsigned int irm = 0; 308 309 switch (routing_mode) { 310 case INTR_ROUTING_MODE_PE: 311 assert(plat_core_pos_by_mpidr(mpidr) >= 0); 312 irm = GICV3_IRM_PE; 313 break; 314 case INTR_ROUTING_MODE_ANY: 315 irm = GICV3_IRM_ANY; 316 break; 317 default: 318 assert(0); /* Unreachable */ 319 break; 320 } 321 322 gicv3_set_spi_routing(id, irm, mpidr); 323 } 324 325 void plat_ic_set_interrupt_pending(unsigned int id) 326 { 327 /* Disallow setting SGIs pending */ 328 assert(id >= MIN_PPI_ID); 329 gicv3_set_interrupt_pending(id, plat_my_core_pos()); 330 } 331 332 void plat_ic_clear_interrupt_pending(unsigned int id) 333 { 334 /* Disallow setting SGIs pending */ 335 assert(id >= MIN_PPI_ID); 336 gicv3_clear_interrupt_pending(id, plat_my_core_pos()); 337 } 338 339 unsigned int plat_ic_set_priority_mask(unsigned int mask) 340 { 341 return gicv3_set_pmr(mask); 342 } 343 344 unsigned int plat_ic_get_interrupt_id(unsigned int raw) 345 { 346 unsigned int id = raw & INT_ID_MASK; 347 348 return gicv3_is_intr_id_special_identifier(id) ? 349 INTR_ID_UNAVAILABLE : id; 350 } 351 #endif 352 #ifdef IMAGE_BL32 353 354 #pragma weak plat_ic_get_pending_interrupt_id 355 #pragma weak plat_ic_acknowledge_interrupt 356 #pragma weak plat_ic_end_of_interrupt 357 358 /* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */ 359 #ifndef __aarch64__ 360 #define IS_IN_EL1() IS_IN_SECURE() 361 #endif 362 363 /* 364 * This function returns the highest priority pending interrupt at 365 * the Interrupt controller 366 */ 367 uint32_t plat_ic_get_pending_interrupt_id(void) 368 { 369 unsigned int irqnr; 370 371 assert(IS_IN_EL1()); 372 irqnr = gicv3_get_pending_interrupt_id_sel1(); 373 return (irqnr == GIC_SPURIOUS_INTERRUPT) ? 374 INTR_ID_UNAVAILABLE : irqnr; 375 } 376 377 /* 378 * This function returns the highest priority pending interrupt at 379 * the Interrupt controller and indicates to the Interrupt controller 380 * that the interrupt processing has started. 381 */ 382 uint32_t plat_ic_acknowledge_interrupt(void) 383 { 384 assert(IS_IN_EL1()); 385 return gicv3_acknowledge_interrupt_sel1(); 386 } 387 388 /* 389 * This functions is used to indicate to the interrupt controller that 390 * the processing of the interrupt corresponding to the `id` has 391 * finished. 392 */ 393 void plat_ic_end_of_interrupt(uint32_t id) 394 { 395 assert(IS_IN_EL1()); 396 gicv3_end_of_interrupt_sel1(id); 397 } 398 #endif 399