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