Changeset 108427 in vbox for trunk/src/VBox/VMM/VMMAll/GICAll.cpp
- Timestamp:
- Mar 4, 2025 8:21:36 AM (7 weeks ago)
- svn:sync-xref-src-repo-rev:
- 167801
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/GICAll.cpp
r107984 r108427 44 44 45 45 /********************************************************************************************************************************* 46 * Internal Functions*46 * Defined Constants And Macros * 47 47 *********************************************************************************************************************************/ 48 49 50 /********************************************************************************************************************************* 51 * Global Variables * 52 *********************************************************************************************************************************/ 48 #define GIC_IS_INTR_SGI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_SGI_RANGE_SIZE) 49 #define GIC_IS_INTR_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_PPI_START < GIC_INTID_PPI_RANGE_SIZE) 50 #define GIC_IS_INTR_SGI_OR_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_PPI_RANGE_SIZE) 51 #define GIC_IS_INTR_SPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SPI_START < GIC_INTID_SPI_RANGE_SIZE) 52 #define GIC_IS_INTR_SPECIAL(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SPECIAL_START < GIC_INTID_EXT_PPI_RANGE_SIZE) 53 #define GIC_IS_INTR_EXT_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE) 54 #define GIC_IS_INTR_EXT_SPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE) 55 53 56 54 57 #ifdef LOG_ENABLED 55 58 /** 56 * Returns a human readable string of the given exception class.57 * 58 * @returns Pointer to the string matching the given EC.59 * @param u32 Ec The exception class to return the string for.60 */ 61 static const char *gicIcc RegisterStringify(uint32_t u32Reg)59 * Gets the description of a CPU interface register. 60 * 61 * @returns The description. 62 * @param u32Reg The CPU interface register offset. 63 */ 64 static const char *gicIccGetRegDescription(uint32_t u32Reg) 62 65 { 63 66 switch (u32Reg) … … 97 100 return "<UNKNOWN>"; 98 101 } 102 103 104 /** 105 * Gets the description of a distributor register given it's register offset. 106 * 107 * @returns The register description. 108 * @param offReg The distributor register offset. 109 */ 110 static const char *gicDistGetRegDescription(uint16_t offReg) 111 { 112 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE) return "GICD_IGROUPRn"; 113 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE) return "GICD_IGROUPRnE"; 114 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE) return "GICD_IROUTERn"; 115 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE) return "GICD_IROUTERnE"; 116 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE) return "GICD_ISENABLERn"; 117 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE) return "GICD_ISENABLERnE"; 118 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE) return "GICD_ICENABLERn"; 119 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE) return "GICD_ICENABLERnE"; 120 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE) return "GICD_ISACTIVERn"; 121 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE) return "GICD_ISACTIVERnE"; 122 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE) return "GICD_ICACTIVERn"; 123 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE) return "GICD_ICACTIVERnE"; 124 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE) return "GICD_IPRIORITYRn"; 125 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE) return "GICD_IPRIORITYRnE"; 126 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE) return "GICD_ISPENDRn"; 127 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE) return "GICD_ISPENDRnE"; 128 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE) return "GICD_ICPENDRn"; 129 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE) return "GICD_ICPENDRnE"; 130 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START < GIC_DIST_REG_ICFGRn_RANGE_SIZE) return "GICD_ICFGRn"; 131 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE) return "GICD_ICFGRnE"; 132 switch (offReg) 133 { 134 case GIC_DIST_REG_CTLR_OFF: return "GICD_CTLR"; 135 case GIC_DIST_REG_TYPER_OFF: return "GICD_TYPER"; 136 case GIC_DIST_REG_STATUSR_OFF: return "GICD_STATUSR"; 137 case GIC_DIST_REG_ITARGETSRn_OFF_START: return "GICD_ITARGETSRn"; 138 case GIC_DIST_REG_IGRPMODRn_OFF_START: return "GICD_IGRPMODRn"; 139 case GIC_DIST_REG_NSACRn_OFF_START: return "GICD_NSACRn"; 140 case GIC_DIST_REG_SGIR_OFF: return "GICD_SGIR"; 141 case GIC_DIST_REG_CPENDSGIRn_OFF_START: return "GICD_CSPENDSGIRn"; 142 case GIC_DIST_REG_SPENDSGIRn_OFF_START: return "GICD_SPENDSGIRn"; 143 case GIC_DIST_REG_INMIn_OFF_START: return "GICD_INMIn"; 144 case GIC_DIST_REG_PIDR2_OFF: return "GICD_PIDR2"; 145 case GIC_DIST_REG_IIDR_OFF: return "GICD_IIDR"; 146 case GIC_DIST_REG_TYPER2_OFF: return "GICD_TYPER2"; 147 default: 148 return "<UNKNOWN>"; 149 } 150 } 151 152 153 /** 154 * Gets the description of a redistributor register given it's register offset. 155 * 156 * @returns The register description. 157 * @param offReg The redistributor register offset. 158 */ 159 static const char *gicReDistGetRegDescription(uint16_t offReg) 160 { 161 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE) return "GICR_IGROUPn"; 162 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE) return "GICR_ISENABLERn"; 163 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE) return "GICR_ICENABLERn"; 164 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE) return "GICR_ISACTIVERn"; 165 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE) return "GICR_ICACTIVERn"; 166 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE) return "GICR_ISPENDRn"; 167 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE) return "GICR_ICPENDRn"; 168 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE) return "GICR_IPREIORITYn"; 169 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE) return "GICR_ICFGRn"; 170 switch (offReg) 171 { 172 case GIC_REDIST_REG_TYPER_OFF: return "GICR_TYPER"; 173 case GIC_REDIST_REG_IIDR_OFF: return "GICR_IIDR"; 174 case GIC_REDIST_REG_TYPER_AFFINITY_OFF: return "GICR_TYPER_AFF"; 175 case GIC_REDIST_REG_PIDR2_OFF: return "GICR_PIDR2"; 176 default: 177 return "<UNKNOWN>"; 178 } 179 } 99 180 #endif 181 182 183 /** 184 * Gets the interrupt ID given a distributor interrupt index. 185 * 186 * @returns The interrupt ID. 187 * @param idxIntr The distributor interrupt index. 188 * @remarks A distributor interrupt is an interrupt type that belong in the 189 * distributor (e.g. SPIs, extended SPIs). 190 */ 191 DECLHIDDEN(uint16_t) gicDistGetIntIdFromIndex(uint16_t idxIntr) 192 { 193 /* 194 * Distributor interrupts bits to interrupt ID mapping: 195 * +--------------------------------------------------------+ 196 * | Range (incl) | SGI | PPI | SPI | Ext SPI | 197 * |--------------+--------+--------+----------+------------| 198 * | Bit | 0..15 | 16..31 | 32..1023 | 1024..2047 | 199 * | Int Id | 0..15 | 16..31 | 32..1023 | 4096..5119 | 200 * +--------------------------------------------------------+ 201 */ 202 uint16_t uIntId; 203 /* SGIs, PPIs, SPIs and specials. */ 204 if (idxIntr < 1024) 205 uIntId = idxIntr; 206 /* Extended SPIs. */ 207 else if (idxIntr < 2048) 208 uIntId = GIC_INTID_RANGE_EXT_SPI_START + idxIntr - 1024; 209 else 210 { 211 uIntId = 0; 212 AssertReleaseFailed(); 213 } 214 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId) 215 || GIC_IS_INTR_SPI(uIntId) 216 || GIC_IS_INTR_SPECIAL(uIntId) 217 || GIC_IS_INTR_EXT_SPI(uIntId)); 218 return uIntId; 219 } 220 221 222 /** 223 * Gets the distributor interrupt index given an interrupt ID. 224 * 225 * @returns The distributor interrupt index. 226 * @param uIntId The interrupt ID. 227 * @remarks A distributor interrupt is an interrupt type that belong in the 228 * distributor (e.g. SPIs, extended SPIs). 229 */ 230 static uint16_t gicDistGetIndexFromIntId(uint16_t uIntId) 231 { 232 uint16_t idxIntr; 233 /* SGIs, PPIs, SPIs and specials. */ 234 if (uIntId <= GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT) 235 idxIntr = uIntId; 236 /* Extended SPIs. */ 237 else if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE) 238 idxIntr = 1024 + uIntId - GIC_INTID_RANGE_EXT_SPI_START; 239 else 240 { 241 idxIntr = 0; 242 AssertReleaseFailed(); 243 } 244 Assert(idxIntr < sizeof(GICDEV::bmIntrPending) * 8); 245 return idxIntr; 246 } 247 248 249 /** 250 * Gets the interrupt ID given a redistributor interrupt index. 251 * 252 * @returns The interrupt ID. 253 * @param idxIntr The redistributor interrupt index. 254 * @remarks A redistributor interrupt is an interrupt type that belong in the 255 * redistributor (e.g. SGIs, PPIs, extended PPIs). 256 */ 257 DECLHIDDEN(uint16_t) gicReDistGetIntIdFromIndex(uint16_t idxIntr) 258 { 259 /* 260 * Redistributor interrupts bits to interrupt ID mapping: 261 * +---------------------------------------------+ 262 * | Range (incl) | SGI | PPI | Ext PPI | 263 * +---------------------------------------------+ 264 * | Bit | 0..15 | 16..31 | 32..95 | 265 * | Int Id | 0..15 | 16..31 | 1056..1119 | 266 * +---------------------------------------------+ 267 */ 268 uint16_t uIntId; 269 /* SGIs and PPIs. */ 270 if (idxIntr < 32) 271 uIntId = idxIntr; 272 /* Extended PPIs. */ 273 else if (idxIntr < 96) 274 uIntId = GIC_INTID_RANGE_PPI_LAST + 1 + idxIntr - GIC_INTID_RANGE_EXT_PPI_START; 275 else 276 { 277 uIntId = 0; 278 AssertReleaseFailed(); 279 } 280 Assert(GIC_IS_INTR_SGI_OR_PPI(uIntId) || GIC_IS_INTR_EXT_PPI(uIntId)); 281 return uIntId; 282 } 283 284 285 /** 286 * Gets the redistributor interrupt index given an interrupt ID. 287 * 288 * @returns The interrupt ID. 289 * @param idxIntr 290 * @remarks A redistributor interrupt is an interrupt type that belong in the 291 * redistributor (e.g. SGIs, PPIs, extended PPIs). 292 */ 293 static uint16_t gicReDistGetIndexFromIntId(uint16_t uIntId) 294 { 295 /* SGIs and PPIs. */ 296 uint16_t idxIntr; 297 if (uIntId <= GIC_INTID_RANGE_PPI_LAST) 298 idxIntr = uIntId; 299 /* Extended PPIs. */ 300 else if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE) 301 idxIntr = 32 + uIntId - GIC_INTID_RANGE_EXT_PPI_START; 302 else 303 { 304 idxIntr = 0; 305 AssertReleaseFailed(); 306 } 307 Assert(idxIntr < sizeof(GICCPU::bmIntrPending) * 8); 308 return idxIntr; 309 } 100 310 101 311 … … 129 339 /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */ 130 340 #if defined(IN_RING0) 131 PVMCC pVM = pVCpu->CTX_SUFF(pVM); 132 VMCPUID idCpu = pVCpu->idCpu; 133 if (VMMGetCpuId(pVM) != idCpu) 134 { 135 switch (VMCPU_GET_STATE(pVCpu)) 136 { 137 case VMCPUSTATE_STARTED_EXEC: 138 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_EXEC\n", idCpu)); 139 GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu); 140 break; 141 142 case VMCPUSTATE_STARTED_HALTED: 143 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_HALTED\n", idCpu)); 144 GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu); 145 break; 146 147 default: 148 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState)); 149 break; /* nothing to do in other states. */ 150 } 151 } 341 # error "Implement me!" 152 342 #elif defined(IN_RING3) 153 343 PVMCC pVM = pVCpu->CTX_SUFF(pVM); … … 162 352 163 353 164 /** 165 * Clears the interrupt pending force-flag. 166 * 167 * @param pVCpu The cross context virtual CPU structure. 168 * @param fIrq Flag whether to clear the IRQ flag. 169 * @param fFiq Flag whether to clear the FIQ flag. 170 */ 171 DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq) 172 { 173 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", 174 pVCpu, pVCpu->idCpu, fIrq, fFiq)); 175 176 Assert(fIrq || fFiq); 177 354 #if 0 355 /** 356 * Sets the update interrupt force-flag and pokes the EMT if required. 357 * 358 * @param pVCpu The cross context virtual CPU structure. 359 */ 360 static void gicSetUpdateInterruptFF(PVMCPUCC pVCpu) 361 { 178 362 #ifdef IN_RING3 179 363 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */ … … 181 365 #endif 182 366 367 /* Set the update-interrupt force-flag. */ 368 VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_GIC); 369 370 /* Wake up the target CPU if we're not currently on the target EMT. */ 371 #if defined(IN_RING0) 372 # error "Implement me" 373 #elif defined(IN_RING3) 374 if (pVCpu->hNativeThread != RTThreadNativeSelf()) 375 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE); 376 #endif 377 } 378 #endif 379 380 381 /** 382 * Clears the interrupt pending force-flag. 383 * 384 * @param pVCpu The cross context virtual CPU structure. 385 * @param fIrq Flag whether to clear the IRQ flag. 386 * @param fFiq Flag whether to clear the FIQ flag. 387 */ 388 DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq) 389 { 390 Assert(fIrq || fFiq); 391 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq)); 392 393 #ifdef IN_RING3 394 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */ 395 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3)); 396 #endif 397 183 398 if (fIrq) 184 399 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ); … … 188 403 189 404 405 /** 406 * Updates the interrupt force-flag. 407 * 408 * @param pVCpu The cross context virtual CPU structure. 409 * @param fIrq Flag whether to clear the IRQ flag. 410 * @param fFiq Flag whether to clear the FIQ flag. 411 */ 190 412 DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq) 191 413 { 192 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", 193 pVCpu, pVCpu->idCpu, fIrq, fFiq)); 414 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq)); 194 415 195 416 if (fIrq || fFiq) … … 201 422 202 423 203 DECLINLINE(void) gicReDistHasIrqPending(PGICCPU pThis, bool *pfIrq, bool *pfFiq) 204 { 424 /** 425 * Gets whether the redistributor has pending interrupts with sufficient priority to 426 * be signalled to the PE. 427 * 428 * @param pGicCpu The GIC redistributor and CPU interface state. 429 * @param pfIrq Where to store whether IRQs can be signalled. 430 * @param pfFiq Where to store whether FIQs can be signalled. 431 */ 432 DECLINLINE(void) gicReDistHasIrqPending(PCGICCPU pGicCpu, bool *pfIrq, bool *pfFiq) 433 { 434 LogFlowFunc(("\n")); 435 #if 0 205 436 /* Read the interrupt state. */ 206 437 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0); … … 246 477 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n", 247 478 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq)); 248 } 249 250 251 DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, PGICCPU pGicVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq) 252 { 479 #else 480 bool const fIsGroup1Enabled = pGicCpu->fIrqGrp1Enabled; 481 bool const fIsGroup0Enabled = pGicCpu->fIrqGrp0Enabled; 482 LogFlowFunc(("fIsGroup0Enabled=%RTbool fIsGroup1Enabled=%RTbool\n", fIsGroup0Enabled, fIsGroup1Enabled)); 483 484 uint32_t bmIntrs[3]; 485 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++) 486 { 487 /* Collect interrupts that are pending, enabled and inactive. */ 488 bmIntrs[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i]; 489 490 /* Discard interrupts if the group they belong to is disabled. */ 491 if (!fIsGroup1Enabled) 492 bmIntrs[i] &= ~pGicCpu->bmIntrGroup[i]; 493 if (!fIsGroup0Enabled) 494 bmIntrs[i] &= pGicCpu->bmIntrGroup[i]; 495 } 496 497 /* Only allow interrupts with higher priority than the current configured and running one. */ 498 uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]); 499 500 uint32_t const cIntrs = sizeof(bmIntrs) * 8; 501 int32_t idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs); 502 AssertCompile(!(cIntrs % 32)); 503 if (idxIntr >= 0) 504 { 505 do 506 { 507 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority)); 508 if (pGicCpu->abIntrPriority[idxIntr] < bPriority) 509 { 510 bool const fInGroup1 = ASMBitTest(&pGicCpu->bmIntrGroup[0], idxIntr); 511 bool const fInGroup0 = !fInGroup1; 512 *pfIrq = fInGroup1 && fIsGroup1Enabled; 513 *pfFiq = fInGroup0 && fIsGroup0Enabled; 514 return; 515 } 516 idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr); 517 } while (idxIntr != -1); 518 } 519 *pfIrq = false; 520 *pfFiq = false; 521 #endif 522 } 523 524 525 /** 526 * Gets whether the distributor has pending interrupts with sufficient priority to 527 * be signalled to the PE. 528 * 529 * @param pGicDev The GIC distributor state. 530 * @param pVCpu The cross context virtual CPU structure. 531 * @param idCpu The ID of the virtual CPU. 532 * @param pfIrq Where to store whether there are IRQs can be signalled. 533 * @param pfFiq Where to store whether there are FIQs can be signalled. 534 */ 535 DECLINLINE(void) gicDistHasIrqPendingForVCpu(PCGICDEV pGicDev, PCVMCPUCC pVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq) 536 { 537 LogFlowFunc(("\n")); 538 #if 0 253 539 /* Read the interrupt state. */ 254 540 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0); … … 296 582 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n", 297 583 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq)); 584 #else 585 bool const fIsGroup1Enabled = pGicDev->fIrqGrp1Enabled; 586 bool const fIsGroup0Enabled = pGicDev->fIrqGrp0Enabled; 587 LogFlowFunc(("fIsGroup1Enabled=%RTbool fIsGroup0Enabled=%RTbool\n", fIsGroup1Enabled, fIsGroup0Enabled)); 588 589 uint32_t bmIntrs[64]; 590 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++) 591 { 592 /* Collect interrupts that are pending, enabled and inactive. */ 593 bmIntrs[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i]; 594 595 /* Discard interrupts if the group they belong to is disabled. */ 596 if (!fIsGroup1Enabled) 597 bmIntrs[i] &= ~pGicDev->bmIntrGroup[i]; 598 if (!fIsGroup0Enabled) 599 bmIntrs[i] &= pGicDev->bmIntrGroup[i]; 600 } 601 602 /* Only allow interrupts with higher priority than the current configured and running one. */ 603 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 604 uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]); 605 606 /* 607 * The distributor's interrupt pending/enabled/active bitmaps have 2048 bits which map 608 * SGIs (16), PPIs (16), SPIs (988), reserved SPIs (4) and extended SPIs (1024). 609 * Of these, the first 16 bits corresponding to SGIs and PPIs are RAZ/WI when affinity 610 * routing is enabled (which it always is in our implementation). 611 */ 612 Assert(pGicDev->fAffRoutingEnabled); 613 uint32_t const cIntrs = sizeof(bmIntrs) * 8; 614 int32_t idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs); 615 AssertCompile(!(cIntrs % 32)); 616 Assert(bmIntrs[0] == 0); 617 if (idxIntr >= 0) 618 { 619 Assert(idxIntr > GIC_INTID_RANGE_PPI_LAST); 620 do 621 { 622 AssertCompile(RT_ELEMENTS(pGicDev->abIntrPriority) == RT_ELEMENTS(pGicDev->au32IntrRouting)); 623 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority)); 624 Assert(idxIntr < GIC_INTID_RANGE_SPECIAL_START || idxIntr > GIC_INTID_RANGE_SPECIAL_LAST); 625 if ( pGicDev->abIntrPriority[idxIntr] < bPriority 626 && pGicDev->au32IntrRouting[idxIntr] == idCpu) 627 { 628 bool const fInGroup1 = ASMBitTest(&pGicDev->bmIntrGroup[0], idxIntr); 629 bool const fInGroup0 = !fInGroup1; 630 *pfFiq = fInGroup0 && fIsGroup0Enabled; 631 *pfIrq = fInGroup1 && fIsGroup1Enabled; 632 return; 633 } 634 idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr); 635 } while (idxIntr != -1); 636 } 637 *pfIrq = false; 638 *pfFiq = false; 639 #endif 298 640 } 299 641 … … 304 646 * 305 647 * @returns Strict VBox status code. 306 * @param pThis The GIC re-distributor state for the associated vCPU. 307 * @param pVCpu The cross context virtual CPU structure. 308 */ 309 static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu) 310 { 311 bool fIrq, fFiq; 312 gicReDistHasIrqPending(pThis, &fIrq, &fFiq); 313 314 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu); 315 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 316 bool fIrqDist, fFiqDist; 317 gicDistHasIrqPendingForVCpu(pGicDev, pThis, pVCpu->idCpu, &fIrqDist, &fFiqDist); 648 * @param pGicDev The GIC distributor state. 649 * @param pVCpu The cross context virtual CPU structure. 650 */ 651 static VBOXSTRICTRC gicReDistUpdateIrqState(PCGICDEV pGicDev, PVMCPUCC pVCpu) 652 { 653 LogFlowFunc(("\n")); 654 bool fIrq; 655 bool fFiq; 656 gicReDistHasIrqPending(VMCPU_TO_GICCPU(pVCpu), &fIrq, &fFiq); 657 LogFlowFunc(("fIrq=%RTbool fFiq=%RTbool\n", fIrq, fFiq)); 658 659 bool fIrqDist; 660 bool fFiqDist; 661 gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, pVCpu->idCpu, &fIrqDist, &fFiqDist); 662 LogFlowFunc(("fIrqDist=%RTbool fFiqDist=%RTbool\n", fIrqDist, fFiqDist)); 663 318 664 fIrq |= fIrqDist; 319 665 fFiq |= fFiqDist; 320 321 666 gicUpdateInterruptFF(pVCpu, fIrq, fFiq); 322 667 return VINF_SUCCESS; … … 328 673 * 329 674 * @returns Strict VBox status code. 330 * @param pVM The cross context VM state. 331 * @param pThis The GIC distributor state. 332 */ 333 static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis) 334 { 675 * @param pVM The cross context VM state. 676 * @param pGicDev The GIC distributor state. 677 */ 678 static VBOXSTRICTRC gicDistUpdateIrqState(PCVMCC pVM, PCGICDEV pGicDev) 679 { 680 LogFlowFunc(("\n")); 335 681 for (uint32_t i = 0; i < pVM->cCpus; i++) 336 682 { 337 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i];338 P GICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);683 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i]; 684 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 339 685 340 686 bool fIrq, fFiq; 341 gicReDistHasIrqPending(pGic VCpu, &fIrq, &fFiq);687 gicReDistHasIrqPending(pGicCpu, &fIrq, &fFiq); 342 688 343 689 bool fIrqDist, fFiqDist; 344 gicDistHasIrqPendingForVCpu(p This, pGicVCpu, i, &fIrqDist, &fFiqDist);690 gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, i, &fIrqDist, &fFiqDist); 345 691 fIrq |= fIrqDist; 346 692 fFiq |= fFiqDist; … … 353 699 354 700 /** 355 * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU. 356 * 357 * @returns VBox status code. 358 * @param pVCpu The cross context virtual CPU structure. 359 * @param uIntId The SGI/PPI interrupt identifier. 360 * @param fAsserted Flag whether the SGI/PPI interrupt is asserted or not. 361 */ 362 static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted) 363 { 364 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu); 365 366 /* Update the interrupts pending state. */ 367 if (fAsserted) 368 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId)); 701 * Reads the distributor's interrupt routing register (GICD_IROUTER). 702 * 703 * @returns Strict VBox status code. 704 * @param pGicDev The GIC distributor state. 705 * @param idxReg The index of the register in the GICD_IROUTER range. 706 * @param puValue Where to store the register's value. 707 */ 708 static VBOXSTRICTRC gicDistReadIntrRoutingReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 709 { 710 /* When affinity routing is disabled, reads return 0. */ 711 Assert(pGicDev->fAffRoutingEnabled); 712 713 /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */ 714 idxReg += GIC_INTID_RANGE_SPI_START; 715 AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW); 716 Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8); 717 if (!(idxReg % 2)) 718 { 719 /* Lower 32-bits. */ 720 uint8_t const fIrm = ASMBitTest(&pGicDev->bmIntrRoutingMode[0], idxReg); 721 *puValue = GIC_DIST_REG_IROUTERn_SET(fIrm, pGicDev->au32IntrRouting[idxReg]); 722 } 369 723 else 370 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId)); 371 372 return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu)); 373 } 374 375 376 /** 377 * Reads a GIC distributor register. 724 { 725 /* Upper 32-bits. */ 726 *puValue = pGicDev->au32IntrRouting[idxReg] >> 24; 727 } 728 729 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue)); 730 return VINF_SUCCESS; 731 } 732 733 734 /** 735 * Writes the distributor's interrupt routing register (GICD_IROUTER). 736 * 737 * @returns Strict VBox status code. 738 * @param pGicDev The GIC distributor state. 739 * @param offReg The offset of the register in the distributor register map. 740 * @param idxReg The index of the register in the GICD_IROUTER range. 741 * @param uValue The value to write to the register. 742 */ 743 static VBOXSTRICTRC gicDistWriteIntrRoutingReg(PGICDEV pGicDev, uint16_t offReg, uint16_t idxReg, uint32_t uValue) 744 { 745 /* When affinity routing is disabled, writes are ignored. */ 746 Assert(pGicDev->fAffRoutingEnabled); 747 748 /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */ 749 idxReg += GIC_INTID_RANGE_SPI_START; 750 AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW); 751 Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8); 752 if (!(offReg & 4)) 753 { 754 /* Lower 32-bits. */ 755 bool const fIrm = GIC_DIST_REG_IROUTERn_IRM_GET(uValue); 756 if (fIrm) 757 ASMBitSet(&pGicDev->bmIntrRoutingMode[0], idxReg); 758 else 759 ASMBitClear(&pGicDev->bmIntrRoutingMode[0], idxReg); 760 uint32_t const fAff3 = pGicDev->au32IntrRouting[idxReg] & 0xff000000; 761 pGicDev->au32IntrRouting[idxReg] = fAff3 | (uValue & 0x00ffffff); 762 } 763 else 764 { 765 /* Upper 32-bits. */ 766 uint32_t const fAffOthers = pGicDev->au32IntrRouting[idxReg] & 0x00ffffff; 767 pGicDev->au32IntrRouting[idxReg] = (uValue << 24) | fAffOthers; 768 } 769 770 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->au32IntrRouting[idxReg])); 771 return VINF_SUCCESS; 772 } 773 774 775 /** 776 * Reads the distributor's interrupt (set/clear) enable register (GICD_ISENABLER and 777 * GICD_ICENABLER). 778 * 779 * @returns Strict VBox status code. 780 * @param pGicDev The GIC distributor state. 781 * @param idxReg The index of the register in the GICD_ISENABLER and 782 * GICD_ICENABLER range. 783 * @param puValue Where to store the register's value. 784 */ 785 static VBOXSTRICTRC gicDistReadIntrEnableReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 786 { 787 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled)); 788 *puValue = pGicDev->bmIntrEnabled[idxReg]; 789 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg])); 790 return VINF_SUCCESS; 791 } 792 793 794 /** 795 * Writes the distributor's interrupt set-enable register (GICD_ISENABLER). 796 * 797 * @returns Strict VBox status code. 798 * @param pVM The cross context VM structure. 799 * @param pGicDev The GIC distributor state. 800 * @param idxReg The index of the register in the GICD_ISENABLER range. 801 * @param uValue The value to write to the register. 802 */ 803 static VBOXSTRICTRC gicDistWriteIntrSetEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 804 { 805 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 806 Assert(pGicDev->fAffRoutingEnabled); 807 if (idxReg > 0) 808 { 809 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled)); 810 pGicDev->bmIntrEnabled[idxReg] |= uValue; 811 return gicDistUpdateIrqState(pVM, pGicDev); 812 } 813 else 814 AssertReleaseFailed(); 815 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg])); 816 return VINF_SUCCESS; 817 } 818 819 820 /** 821 * Writes the distributor's interrupt clear-enable register (GICD_ICENABLER). 822 * 823 * @returns Strict VBox status code. 824 * @param pVM The cross context VM structure. 825 * @param pGicDev The GIC distributor state. 826 * @param idxReg The index of the register in the GICD_ICENABLER range. 827 * @param uValue The value to write to the register. 828 */ 829 static VBOXSTRICTRC gicDistWriteIntrClearEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 830 { 831 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 832 Assert(pGicDev->fAffRoutingEnabled); 833 if (idxReg > 0) 834 { 835 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled)); 836 pGicDev->bmIntrEnabled[idxReg] &= ~uValue; 837 return gicDistUpdateIrqState(pVM, pGicDev); 838 } 839 else 840 AssertReleaseFailed(); 841 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg])); 842 return VINF_SUCCESS; 843 } 844 845 846 /** 847 * Reads the distributor's interrupt active register (GICD_ISACTIVER and 848 * GICD_ICACTIVER). 849 * 850 * @returns Strict VBox status code. 851 * @param pGicDev The GIC distributor state. 852 * @param idxReg The index of the register in the GICD_ISACTIVER and 853 * GICD_ICACTIVER range. 854 * @param puValue Where to store the register's value. 855 */ 856 static VBOXSTRICTRC gicDistReadIntrActiveReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 857 { 858 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive)); 859 *puValue = pGicDev->bmIntrActive[idxReg]; 860 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrActive[idxReg])); 861 return VINF_SUCCESS; 862 } 863 864 865 /** 866 * Writes the distributor's interrupt set-active register (GICD_ISACTIVER). 867 * 868 * @returns Strict VBox status code. 869 * @param pVM The cross context VM structure. 870 * @param pGicDev The GIC distributor state. 871 * @param idxReg The index of the register in the GICD_ISACTIVER range. 872 * @param uValue The value to write to the register. 873 */ 874 static VBOXSTRICTRC gicDistWriteIntrSetActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 875 { 876 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 877 Assert(pGicDev->fAffRoutingEnabled); 878 if (idxReg > 0) 879 { 880 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive)); 881 pGicDev->bmIntrActive[idxReg] |= uValue; 882 return gicDistUpdateIrqState(pVM, pGicDev); 883 } 884 else 885 AssertReleaseFailed(); 886 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg])); 887 return VINF_SUCCESS; 888 } 889 890 891 /** 892 * Writes the distributor's interrupt clear-active register (GICD_ICACTIVER). 893 * 894 * @returns Strict VBox status code. 895 * @param pVM The cross context VM structure. 896 * @param pGicDev The GIC distributor state. 897 * @param idxReg The index of the register in the GICD_ICACTIVER range. 898 * @param uValue The value to write to the register. 899 */ 900 static VBOXSTRICTRC gicDistWriteIntrClearActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 901 { 902 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 903 Assert(pGicDev->fAffRoutingEnabled); 904 if (idxReg > 0) 905 { 906 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive)); 907 pGicDev->bmIntrActive[idxReg] &= ~uValue; 908 return gicDistUpdateIrqState(pVM, pGicDev); 909 } 910 else 911 AssertReleaseFailed(); 912 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg])); 913 return VINF_SUCCESS; 914 } 915 916 917 /** 918 * Reads the distributor's interrupt priority register (GICD_IPRIORITYR). 919 * 920 * @returns Strict VBox status code. 921 * @param pGicDev The GIC distributor state. 922 * @param idxReg The index of the register in the GICD_IPRIORITY range. 923 * @param puValue Where to store the register's value. 924 */ 925 static VBOXSTRICTRC gicDistReadIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 926 { 927 /* When affinity routing is enabled, reads to registers 0..7 (pertaining to SGIs and PPIs) return 0. */ 928 Assert(pGicDev->fAffRoutingEnabled); 929 Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t)); 930 Assert(idxReg != 255); 931 if (idxReg > 7) 932 { 933 uint16_t const idxPriority = idxReg * sizeof(uint32_t); 934 AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW); 935 AssertCompile(sizeof(*puValue) == sizeof(uint32_t)); 936 *puValue = *(uint32_t *)&pGicDev->abIntrPriority[idxPriority]; 937 } 938 else 939 { 940 AssertReleaseFailed(); 941 *puValue = 0; 942 } 943 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue)); 944 return VINF_SUCCESS; 945 } 946 947 948 /** 949 * Writes the distributor's interrupt priority register (GICD_IPRIORITYR). 950 * 951 * @returns Strict VBox status code. 952 * @param pGicDev The GIC distributor state. 953 * @param idxReg The index of the register in the GICD_IPRIORITY range. 954 * @param uValue The value to write to the register. 955 */ 956 static VBOXSTRICTRC gicDistWriteIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 957 { 958 /* When affinity routing is enabled, writes to registers 0..7 are ignored. */ 959 Assert(pGicDev->fAffRoutingEnabled); 960 Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t)); 961 Assert(idxReg != 255); 962 if (idxReg > 7) 963 { 964 uint16_t const idxPriority = idxReg * sizeof(uint32_t); 965 AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW); 966 AssertCompile(sizeof(uValue) == sizeof(uint32_t)); 967 *(uint32_t *)&pGicDev->abIntrPriority[idxPriority] = uValue; 968 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicDev->abIntrPriority[idxPriority])); 969 } 970 else 971 AssertReleaseFailed(); 972 return VINF_SUCCESS; 973 } 974 975 976 /** 977 * Reads the distributor's interrupt pending register (GICD_ISPENDR and 978 * GICD_ICPENDR). 979 * 980 * @returns Strict VBox status code. 981 * @param pGicDev The GIC distributor state. 982 * @param idxReg The index of the register in the GICD_ISPENDR and 983 * GICD_ICPENDR range. 984 * @param puValue Where to store the register's value. 985 */ 986 static VBOXSTRICTRC gicDistReadIntrPendingReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 987 { 988 /* When affinity routing is enabled, reads for SGIs and PPIs return 0. */ 989 Assert(pGicDev->fAffRoutingEnabled); 990 if (idxReg > 0) 991 { 992 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending)); 993 *puValue = pGicDev->bmIntrPending[idxReg]; 994 } 995 else 996 { 997 AssertReleaseFailed(); 998 *puValue = 0; 999 } 1000 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrPending[idxReg])); 1001 return VINF_SUCCESS; 1002 } 1003 1004 1005 /** 1006 * Write's the distributor's interrupt set-pending register (GICD_ISPENDR). 1007 * 1008 * @returns Strict VBox status code. 1009 * @param pVM The cross context VM structure. 1010 * @param pGicDev The GIC distributor state. 1011 * @param idxReg The index of the register in the GICD_ISPENDR range. 1012 * @param uValue The value to write to the register. 1013 */ 1014 static VBOXSTRICTRC gicDistWriteIntrSetPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 1015 { 1016 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 1017 Assert(pGicDev->fAffRoutingEnabled); 1018 if (idxReg > 0) 1019 { 1020 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending)); 1021 pGicDev->bmIntrPending[idxReg] |= uValue; 1022 return gicDistUpdateIrqState(pVM, pGicDev); 1023 } 1024 else 1025 AssertReleaseFailed(); 1026 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg])); 1027 return VINF_SUCCESS; 1028 } 1029 1030 1031 /** 1032 * Write's the distributor's interrupt clear-pending register (GICD_ICPENDR). 1033 * 1034 * @returns Strict VBox status code. 1035 * @param pVM The cross context VM structure. 1036 * @param pGicDev The GIC distributor state. 1037 * @param idxReg The index of the register in the GICD_ICPENDR range. 1038 * @param uValue The value to write to the register. 1039 */ 1040 static VBOXSTRICTRC gicDistWriteIntrClearPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 1041 { 1042 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 1043 Assert(pGicDev->fAffRoutingEnabled); 1044 if (idxReg > 0) 1045 { 1046 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending)); 1047 pGicDev->bmIntrPending[idxReg] &= ~uValue; 1048 return gicDistUpdateIrqState(pVM, pGicDev); 1049 } 1050 else 1051 AssertReleaseFailed(); 1052 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg])); 1053 return VINF_SUCCESS; 1054 } 1055 1056 1057 /** 1058 * Reads the distributor's interrupt config register (GICD_ICFGR). 1059 * 1060 * @returns Strict VBox status code. 1061 * @param pGicDev The GIC distributor state. 1062 * @param idxReg The index of the register in the GICD_ICFGR range. 1063 * @param puValue Where to store the register's value. 1064 */ 1065 static VBOXSTRICTRC gicDistReadIntrConfigReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 1066 { 1067 /* SGIs are read-only and are always edge-triggered. */ 1068 if (idxReg > 0) 1069 { 1070 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig)); 1071 *puValue = pGicDev->bmIntrConfig[idxReg]; 1072 } 1073 else 1074 *puValue = 0xaaaaaaaa; 1075 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg])); 1076 return VINF_SUCCESS; 1077 } 1078 1079 1080 /** 1081 * Writes the distributor's interrupt config register (GICD_ICFGR). 1082 * 1083 * @returns Strict VBox status code. 1084 * @param pGicDev The GIC distributor state. 1085 * @param idxReg The index of the register in the GICD_ICFGR range. 1086 * @param uValue The value to write to the register. 1087 */ 1088 static VBOXSTRICTRC gicDistWriteIntrConfigReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 1089 { 1090 /* Writes to SGIs are ignored. */ 1091 if (idxReg > 0) 1092 { 1093 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig)); 1094 pGicDev->bmIntrConfig[idxReg] = uValue; 1095 } 1096 else 1097 AssertReleaseFailed(); 1098 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg])); 1099 return VINF_SUCCESS; 1100 } 1101 1102 1103 /** 1104 * Reads the distributor's interrupt config register (GICD_IGROUPR). 1105 * 1106 * @returns Strict VBox status code. 1107 * @param pGicDev The GIC distributor state. 1108 * @param idxReg The index of the register in the GICD_IGROUPR range. 1109 * @param puValue Where to store the register's value. 1110 */ 1111 static VBOXSTRICTRC gicDistReadIntrGroupReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue) 1112 { 1113 /* When affinity routing is enabled, reads to SGIs and PPIs return 0. */ 1114 Assert(pGicDev->fAffRoutingEnabled); 1115 if (idxReg > 0) 1116 { 1117 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrGroup)); 1118 *puValue = pGicDev->bmIntrGroup[idxReg]; 1119 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue)); 1120 } 1121 else 1122 AssertReleaseFailed(); 1123 return VINF_SUCCESS; 1124 } 1125 1126 1127 /** 1128 * Writes the distributor's interrupt config register (GICD_ICFGR). 1129 * 1130 * @returns Strict VBox status code. 1131 * @param pVM The cross context VM structure. 1132 * @param pGicDev The GIC distributor state. 1133 * @param idxReg The index of the register in the GICD_ICFGR range. 1134 * @param uValue The value to write to the register. 1135 */ 1136 static VBOXSTRICTRC gicDistWriteIntrGroupReg(PCVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue) 1137 { 1138 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */ 1139 Assert(pGicDev->fAffRoutingEnabled); 1140 if (idxReg > 0) 1141 { 1142 pGicDev->bmIntrGroup[idxReg] = uValue; 1143 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrGroup[idxReg])); 1144 } 1145 else 1146 AssertReleaseFailed(); 1147 return gicDistUpdateIrqState(pVM, pGicDev); 1148 } 1149 1150 1151 /** 1152 * Reads the redistributor's interrupt priority register (GICR_IPRIORITYR). 1153 * 1154 * @returns Strict VBox status code. 1155 * @param pGicDev The GIC distributor state. 1156 * @param pGicCpu The GIC redistributor and CPU interface state. 1157 * @param idxReg The index of the register in the GICR_IPRIORITY range. 1158 * @param puValue Where to store the register's value. 1159 */ 1160 static VBOXSTRICTRC gicReDistReadIntrPriorityReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1161 { 1162 /* When affinity routing is disabled, reads return 0. */ 1163 Assert(pGicDev->fAffRoutingEnabled); 1164 uint16_t const idxPriority = idxReg * sizeof(uint32_t); 1165 AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW); 1166 AssertCompile(sizeof(*puValue) == sizeof(uint32_t)); 1167 *puValue = *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority]; 1168 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue)); 1169 return VINF_SUCCESS; 1170 } 1171 1172 1173 /** 1174 * Writes the redistributor's interrupt priority register (GICR_IPRIORITYR). 1175 * 1176 * @returns Strict VBox status code. 1177 * @param pGicDev The GIC distributor state. 1178 * @param pVCpu The cross context virtual CPU structure. 1179 * @param idxReg The index of the register in the GICR_IPRIORITY range. 1180 * @param uValue The value to write to the register. 1181 */ 1182 static VBOXSTRICTRC gicReDistWriteIntrPriorityReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1183 { 1184 /* When affinity routing is disabled, writes are ignored. */ 1185 Assert(pGicDev->fAffRoutingEnabled); 1186 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1187 uint16_t const idxPriority = idxReg * sizeof(uint32_t); 1188 AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW); 1189 AssertCompile(sizeof(uValue) == sizeof(uint32_t)); 1190 *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority] = uValue; 1191 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority])); 1192 return VINF_SUCCESS; 1193 } 1194 1195 1196 /** 1197 * Reads the redistributor's interrupt pending register (GICR_ISPENDR and 1198 * GICR_ICPENDR). 1199 * 1200 * @returns Strict VBox status code. 1201 * @param pGicDev The GIC distributor state. 1202 * @param pGicCpu The GIC redistributor and CPU interface state. 1203 * @param idxReg The index of the register in the GICR_ISPENDR and 1204 * GICR_ICPENDR range. 1205 * @param puValue Where to store the register's value. 1206 */ 1207 static VBOXSTRICTRC gicReDistReadIntrPendingReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1208 { 1209 /* When affinity routing is disabled, reads return 0. */ 1210 Assert(pGicDev->fAffRoutingEnabled); 1211 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending)); 1212 *puValue = pGicCpu->bmIntrPending[idxReg]; 1213 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg])); 1214 return VINF_SUCCESS; 1215 } 1216 1217 1218 /** 1219 * Writes the redistributor's interrupt set-pending register (GICR_ISPENDR). 1220 * 1221 * @returns Strict VBox status code. 1222 * @param pGicDev The GIC distributor state. 1223 * @param pVCpu The cross context virtual CPU structure. 1224 * @param idxReg The index of the register in the GICR_ISPENDR range. 1225 * @param uValue The value to write to the register. 1226 */ 1227 static VBOXSTRICTRC gicReDistWriteIntrSetPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1228 { 1229 /* When affinity routing is disabled, writes are ignored. */ 1230 Assert(pGicDev->fAffRoutingEnabled); 1231 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1232 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending)); 1233 pGicCpu->bmIntrPending[idxReg] |= uValue; 1234 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg])); 1235 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1236 } 1237 1238 1239 /** 1240 * Writes the redistributor's interrupt clear-pending register (GICR_ICPENDR). 1241 * 1242 * @returns Strict VBox status code. 1243 * @param pGicDev The GIC distributor state. 1244 * @param pVCpu The cross context virtual CPU structure. 1245 * @param idxReg The index of the register in the GICR_ICPENDR range. 1246 * @param uValue The value to write to the register. 1247 */ 1248 static VBOXSTRICTRC gicReDistWriteIntrClearPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1249 { 1250 /* When affinity routing is disabled, writes are ignored. */ 1251 Assert(pGicDev->fAffRoutingEnabled); 1252 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1253 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending)); 1254 pGicCpu->bmIntrPending[idxReg] &= ~uValue; 1255 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg])); 1256 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1257 } 1258 1259 1260 /** 1261 * Reads the redistributor's interrupt enable register (GICR_ISENABLER and 1262 * GICR_ICENABLER). 1263 * 1264 * @returns Strict VBox status code. 1265 * @param pGicDev The GIC distributor state. 1266 * @param pGicCpu The GIC redistributor and CPU interface state. 1267 * @param idxReg The index of the register in the GICR_ISENABLER and 1268 * GICR_ICENABLER range. 1269 * @param puValue Where to store the register's value. 1270 */ 1271 static VBOXSTRICTRC gicReDistReadIntrEnableReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1272 { 1273 Assert(pGicDev->fAffRoutingEnabled); 1274 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled)); 1275 *puValue = pGicCpu->bmIntrEnabled[idxReg]; 1276 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg])); 1277 return VINF_SUCCESS; 1278 } 1279 1280 1281 /** 1282 * Writes the redistributor's interrupt set-enable register (GICR_ISENABLER). 1283 * 1284 * @returns Strict VBox status code. 1285 * @param pGicDev The GIC distributor state. 1286 * @param pVCpu The cross context virtual CPU structure. 1287 * @param idxReg The index of the register in the GICR_ISENABLER range. 1288 * @param uValue The value to write to the register. 1289 */ 1290 static VBOXSTRICTRC gicReDistWriteIntrSetEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1291 { 1292 Assert(pGicDev->fAffRoutingEnabled); 1293 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1294 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled)); 1295 pGicCpu->bmIntrEnabled[idxReg] |= uValue; 1296 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg])); 1297 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1298 } 1299 1300 1301 /** 1302 * Writes the redistributor's interrupt clear-enable register (GICR_ICENABLER). 1303 * 1304 * @returns Strict VBox status code. 1305 * @param pGicDev The GIC distributor state. 1306 * @param pVCpu The cross context virtual CPU structure. 1307 * @param idxReg The index of the register in the GICR_ICENABLER range. 1308 * @param uValue The value to write to the register. 1309 */ 1310 static VBOXSTRICTRC gicReDistWriteIntrClearEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1311 { 1312 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1313 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled)); 1314 pGicCpu->bmIntrEnabled[idxReg] &= ~uValue; 1315 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg])); 1316 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1317 } 1318 1319 1320 /** 1321 * Reads the redistributor's interrupt active register (GICR_ISACTIVER and 1322 * GICR_ICACTIVER). 1323 * 1324 * @returns Strict VBox status code. 1325 * @param pGicCpu The GIC redistributor and CPU interface state. 1326 * @param idxReg The index of the register in the GICR_ISACTIVER and 1327 * GICR_ICACTIVER range. 1328 * @param puValue Where to store the register's value. 1329 */ 1330 static VBOXSTRICTRC gicReDistReadIntrActiveReg(PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1331 { 1332 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive)); 1333 *puValue = pGicCpu->bmIntrActive[idxReg]; 1334 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg])); 1335 return VINF_SUCCESS; 1336 } 1337 1338 1339 /** 1340 * Writes the redistributor's interrupt set-active register (GICR_ISACTIVER). 1341 * 1342 * @returns Strict VBox status code. 1343 * @param pGicDev The GIC distributor state. 1344 * @param pVCpu The cross context virtual CPU structure. 1345 * @param idxReg The index of the register in the GICR_ISACTIVER range. 1346 * @param uValue The value to write to the register. 1347 */ 1348 static VBOXSTRICTRC gicReDistWriteIntrSetActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1349 { 1350 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1351 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive)); 1352 pGicCpu->bmIntrActive[idxReg] |= uValue; 1353 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg])); 1354 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1355 } 1356 1357 1358 /** 1359 * Writes the redistributor's interrupt clear-active register (GICR_ICACTIVER). 1360 * 1361 * @returns Strict VBox status code. 1362 * @param pGicDev The GIC distributor state. 1363 * @param pVCpu The cross context virtual CPU structure. 1364 * @param idxReg The index of the register in the GICR_ICACTIVER range. 1365 * @param uValue The value to write to the register. 1366 */ 1367 static VBOXSTRICTRC gicReDistWriteIntrClearActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1368 { 1369 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1370 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive)); 1371 pGicCpu->bmIntrActive[idxReg] &= ~uValue; 1372 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg])); 1373 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1374 } 1375 1376 1377 /** 1378 * Reads the redistributor's interrupt config register (GICR_ICFGR). 1379 * 1380 * @returns Strict VBox status code. 1381 * @param pGicDev The GIC distributor state. 1382 * @param pGicCpu The GIC redistributor and CPU interface state. 1383 * @param idxReg The index of the register in the GICR_ICFGR range. 1384 * @param puValue Where to store the register's value. 1385 */ 1386 static VBOXSTRICTRC gicReDistReadIntrConfigReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1387 { 1388 /* When affinity routing is disabled, reads return 0. */ 1389 Assert(pGicDev->fAffRoutingEnabled); 1390 if (idxReg > 0) 1391 { 1392 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig)); 1393 *puValue = pGicCpu->bmIntrConfig[idxReg]; 1394 } 1395 else 1396 { 1397 /* SGIs are read-only and are always edge-triggered. */ 1398 *puValue = 0xaaaaaaaa; 1399 } 1400 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue)); 1401 return VINF_SUCCESS; 1402 } 1403 1404 1405 /** 1406 * Writes the redistributor's interrupt config register (GICR_ICFGR). 1407 * 1408 * @returns Strict VBox status code. 1409 * @param pGicDev The GIC distributor state. 1410 * @param pVCpu The cross context virtual CPU structure. 1411 * @param idxReg The index of the register in the GICR_ICFGR range. 1412 * @param uValue The value to write to the register. 1413 */ 1414 static VBOXSTRICTRC gicReDistWriteIntrConfigReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1415 { 1416 /* When affinity routing is disabled, writes are ignored. */ 1417 Assert(pGicDev->fAffRoutingEnabled); 1418 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1419 if (idxReg > 0) 1420 { 1421 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig)); 1422 pGicCpu->bmIntrConfig[idxReg] = uValue; 1423 } 1424 else 1425 { 1426 /* SGIs are always edge triggered ignore writes, verify value on strict builds (e.g. aarch64 Win11 writes this). */ 1427 Assert(uValue == 0xaaaaaaaa); 1428 Assert(pGicCpu->bmIntrConfig[0] == uValue); 1429 } 1430 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrConfig[idxReg])); 1431 return VINF_SUCCESS; 1432 } 1433 1434 1435 /** 1436 * Reads the redistributor's interrupt group register (GICD_IGROUPR). 1437 * 1438 * @returns Strict VBox status code. 1439 * @param pGicDev The GIC distributor state. 1440 * @param pGicCpu The GIC redistributor and CPU interface state. 1441 * @param idxReg The index of the register in the GICR_IGROUPR range. 1442 * @param puValue Where to store the register's value. 1443 */ 1444 static VBOXSTRICTRC gicReDistReadIntrGroupReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue) 1445 { 1446 /* When affinity routing is disabled, reads return 0. */ 1447 Assert(pGicDev->fAffRoutingEnabled); 1448 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup)); 1449 *puValue = pGicCpu->bmIntrGroup[idxReg]; 1450 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg])); 1451 return VINF_SUCCESS; 1452 } 1453 1454 1455 /** 1456 * Writes the redistributor's interrupt group register (GICR_IGROUPR). 1457 * 1458 * @returns Strict VBox status code. 1459 * @param pGicDev The GIC distributor state. 1460 * @param pVCpu The cross context virtual CPU structure. 1461 * @param idxReg The index of the register in the GICR_IGROUPR range. 1462 * @param uValue The value to write to the register. 1463 */ 1464 static VBOXSTRICTRC gicReDistWriteIntrGroupReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue) 1465 { 1466 /* When affinity routing is disabled, writes are ignored. */ 1467 Assert(pGicDev->fAffRoutingEnabled); 1468 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1469 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup)); 1470 pGicCpu->bmIntrGroup[idxReg] = uValue; 1471 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg])); 1472 return gicReDistUpdateIrqState(pGicDev, pVCpu); 1473 } 1474 1475 1476 #if 0 1477 /** 1478 * Gets the IDB index for a given interrupt ID. 1479 * 1480 * @returns UINT16_MAX is the interrupt ID is invalid or does not map to an index, 1481 * otherwise returns a valid index. 1482 * @param uIntId The interrupt ID. 1483 */ 1484 static uint16_t gicIntIdToIdbIndex(uint16_t uIntId) 1485 { 1486 /* 1487 * Interrupt Delivery Bitmap (IDB) format; bits to interrupt ID mapping: 1488 * +---------------------------------------------------------------------+ 1489 * | Incl ranges | SGI | PPI | SPI | Ext PPI | Ext SPI | 1490 * +---------------------------------------------------------------------+ 1491 * | Int Id | 0..15 | 16..31 | 32..1019 | 1056..1119 | 4096..5119 | 1492 * | Bit Index | 0..15 | 16..31 | 32..1019 | 1020..1083 | 1084..2107 | 1493 * +---------------------------------------------------------------------+ 1494 */ 1495 uint16_t const idxIdb; 1496 if (uIntId <= GIC_INTID_RANGE_SPI_LAST) 1497 return uIntId; 1498 if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE) 1499 return GIC_INTID_RANGE_EXT_PPI_START + uIntId - GIC_INTID_RANGE_EXT_PPI_START; 1500 if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE) 1501 return GIC_INTID_RANGE_EXT_SPI_START + uIntId - GIC_INTID_RANGE_EXT_SPI_START; 1502 return UINT16_MAX; 1503 } 1504 1505 static bool gicIsIntIdValid(uint16_t uIntId) 1506 { 1507 if (uIntId <= GIC_INTID_RANGE_SPI_LAST) 1508 return true; 1509 if (uIntIt - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE) 1510 return true; 1511 if (uIntIt - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE) 1512 return true; 1513 return false; 1514 } 1515 1516 1517 static void gicSetIdxInIdb(PGICIDB pGicIdb, uint16_t idxIdb) 1518 { 1519 if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8)) 1520 ASMAtomicBitSet(&pGicIdb->au64IntIdBitmap[0], idxIdb); 1521 else 1522 AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId)); 1523 } 1524 1525 1526 /** 1527 * Sets an interrupt ID in an Interrupt-Delivery Bitmap (IDB). 1528 * 1529 * @param pGicIdb Pointer to the IDB. 1530 * @param uIntId The interrupt ID. 1531 */ 1532 static void gicSetIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId) 1533 { 1534 uint16_t const idxIdb = gicIntIdToIdbIndex(uIntId); 1535 gicSetIdxInIdb(pGicIdb, idxIdb); 1536 } 1537 1538 1539 /** 1540 * Clears an interrupt ID in an Interrupt-Delivery Bitmap (IDB). 1541 * 1542 * @param pGicIdb Pointer to the IDB. 1543 * @param uIntId The interrupt ID. 1544 */ 1545 static void gicClearIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId) 1546 { 1547 uint16_t const idxIdb = gicIntIdToIdbIndex(uIntId); 1548 if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8)) 1549 ASMAtomicBitClear(&pGicIdb->au64IntIdBitmap[0], idxIdb); 1550 else 1551 AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId)); 1552 } 1553 1554 1555 /** 1556 * Atomically sets the IDB notification bit. 1557 * 1558 * @returns non-zero if the bit was already set, 0 otherwise. 1559 * @param pGicIdb Pointer to the IDB. 1560 */ 1561 static uint32_t gicSetNotificationBitInIdb(PGICIDB pGicIdb) 1562 { 1563 return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, RT_BIT_32(31)); 1564 } 1565 1566 1567 /** 1568 * Atomically tests and clears the IDB notification bit. 1569 * 1570 * @returns non-zero if the bit was already set, 0 otherwise. 1571 * @param pGicIdb Pointer to the IDB. 1572 */ 1573 static uint32_t gicClearNotificationBitInIdb(PGICIDB pGicIdb) 1574 { 1575 return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, UINT32_C(0)); 1576 } 1577 1578 1579 static VBOXSTRICTRC gicPostInterrupt(PVMCPUCC pVCpu, PVMCPUSET pCpuSet, uint16_t idxIdb) 1580 { 1581 Assert(gicIntIdToIdbIndex(idxIdb) != UINT16_MAX); 1582 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++) 1583 { 1584 if (VMCPUSET_IS_PRESENT(&DestCpuSet, idCpu)) 1585 { 1586 PVMCPUCC pTargetVCpu = pVCpu->pVMR3->CTX_SUFF(apCpus)[idCpu]; 1587 VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, VERR_INVALID_HANDLE); 1588 1589 PGICCPU pTargetGicCpu = VMCPU_TO_GICCPU(pTargetVCpu); 1590 PGICIDB pTargetGicIdb = &pTargetGicCpu->IntrDeliveryBitmap; 1591 gicSetIdxInIdb(pTargetGicIdb, idxIdb); 1592 uint32_t const fAlreadySet = gicSetNotificationBitInIdb(pTargetGicIdb); 1593 if (!fAlreadySet) 1594 gicSetUpdateInterruptFF(pVCpu); 1595 } 1596 } 1597 } 1598 #endif 1599 1600 1601 /** 1602 * Gets the virtual CPUID given the affinity values. 1603 * 1604 * @returns The virtual CPUID. 1605 * @param idCpuInterface The virtual CPUID within the PE cluster (0..15). 1606 * @param uAff1 The affinity 1 value. 1607 * @param uAff2 The affinity 2 value. 1608 * @param uAff3 The affinity 3 value. 1609 */ 1610 DECL_FORCE_INLINE(VMCPUID) gicGetCpuIdFromAffinity(uint8_t idCpuInterface, uint8_t uAff1, uint8_t uAff2, uint8_t uAff3) 1611 { 1612 AssertReturn(idCpuInterface < 16, VERR_INVALID_PARAMETER); 1613 return (uAff3 * 1048576) + (uAff2 * 4096) + (uAff1 * 16) + idCpuInterface; 1614 } 1615 1616 1617 #if 0 1618 /** 1619 * @interface_method_impl{PDMGICBACKEND,pfnUpdatePendingInterrupts} 1620 */ 1621 static DECLCALLBACK(void) gicUpdatePendingInterrupts(PVMCPUCC pVCpu) 1622 { 1623 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu); 1624 1625 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1626 1627 /* 1628 * Delivery interrupts pending in the interrupt-delivery bitmap to the PE. 1629 */ 1630 bool fHasPendingIntrs = false; 1631 PGICIDB pIdb = (PGICIDB)pGicCpu->IntrDeliveryBitmap; 1632 for (;;) 1633 { 1634 uint32_t const fAlreadySet = gicClearNotificationBitInIdb(pIdb); 1635 if (!fAlreadySet) 1636 break; 1637 1638 /* SGI and PPIs */ 1639 uint32_t const uSgiPpi = ASMAtomicXchgU32(&pIdb->au64IntIdBitmap[0], 0); 1640 if (uSgiPpi) 1641 1642 } 1643 1644 STAM_PROFILE_STOP(&pApicCpu->StatUpdatePendingIntrs, a); 1645 Log3(("APIC%u: apicUpdatePendingInterrupts: fHasPendingIntrs=%RTbool\n", pVCpu->idCpu, fHasPendingIntrs)); 1646 1647 if ( fHasPendingIntrs 1648 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC)) 1649 apicSignalNextPendingIntr(pVCpu); 1650 } 1651 #endif 1652 1653 1654 #if 0 1655 static uint16_t gicGetHighestPrioPendingIntrFrom(const void *pvIntrPending, uint32_t cIntrs, uint8_t *pabIntrPriority, 1656 uint32_t cIntrPriority, uint8_t *pbPriority) 1657 { 1658 uint16_t uIntIdHighest = 0; 1659 uint8_t bPriority = UINT8_MAX; 1660 1661 /* Find the INTID and priority of the pending interrupt with the highest priority. */ 1662 int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs); 1663 AssertCompile(!(cIntrs % 32)); 1664 if (idxIntr >= 0) 1665 { 1666 do 1667 { 1668 uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr); 1669 AssertRelease(uIntId < cIntrPriority); 1670 if (pabIntrPriority[uIntId] < bPriority) 1671 { 1672 bPriority = pabIntrPriority[uIntId]; 1673 uIntIdHighest = uIntId; 1674 } 1675 idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr); 1676 } while (idxIntr != -1); 1677 } 1678 else 1679 { 1680 bPriority = UINT8_MAX; 1681 uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1682 } 1683 1684 *pbPriority = bPriority; 1685 return uIntIdHighest; 1686 } 1687 1688 1689 static uint16_t gicDistGetHighestPrioPendingIntr(PCGICDEV pGicDev, uint8_t *pbPriority) 1690 { 1691 uint16_t uIntIdHighest = 0; 1692 uint8_t bPriority = UINT8_MAX; 1693 uint32_t const cIntrs = sizeof(pGicDev->bmIntrPending) * 8; 1694 void const *pvIntrPending = &pGicDev->bmIntrPending[0]; 1695 1696 /* Find the INTID and priority of the pending interrupt with the highest priority. */ 1697 int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs); 1698 AssertCompile(!(cIntrs % 32)); 1699 if (idxIntr >= 0) 1700 { 1701 Assert(!pGicDev->fAffRoutingEnabled || idxIntr >= GIC_INTID_RANGE_SPI_START); 1702 do 1703 { 1704 uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr); 1705 Assert(uIntId < RT_ELEMENTS(pGicDev->abIntrPriority)); 1706 if (pGicDev->abIntrPriority[uIntId] < bPriority) 1707 { 1708 bPriority = pGicDev->abIntrPriority[idxIntr]; 1709 uIntIdHighest = uIntId; 1710 } 1711 idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr); 1712 } while (idxIntr != -1); 1713 } 1714 else 1715 { 1716 bPriority = UINT8_MAX; 1717 uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1718 } 1719 1720 /* Sanity check if the interrupt ID is plausible. */ 1721 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest) 1722 || GIC_IS_INTR_SPI(uIntIdHighest) 1723 || GIC_IS_INTR_EXT_PPI(uIntIdHighest) 1724 || GIC_IS_INTR_EXT_SPI(uIntIdHighest) 1725 || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1726 /* Ensure if no interrupt is pending, priority is appropriate. */ 1727 Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 1728 1729 *pbPriority = bPriority; 1730 return uIntIdHighest; 1731 } 1732 1733 1734 static uint16_t gicDistGetHighestPrioPendingGroupIntr(PCGICDEV pGicDev, uint8_t *pbPriority, bool fGroup0) 1735 { 1736 uint32_t bmIntrPending[64]; 1737 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++) 1738 { 1739 bmIntrPending[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i]; 1740 if (fGroup0) 1741 bmIntrPending[i] &= ~pGicDev->bmIntrGroup[i]; 1742 else 1743 bmIntrPending[i] &= pGicDev->bmIntrGroup[i]; 1744 } 1745 1746 void const *pvIntrPending = &bmIntrPending[0]; 1747 uint32_t const cIntrs = sizeof(bmIntrPending) * 8; 1748 uint16_t const uIntId = gicGetHighestPrioPendingIntrFrom(pvIntrPending, cIntrs, pGicDev->abIntrPriority, 1749 RT_ELEMENTS(pGicDev->abIntrPriority), pbPriority); 1750 1751 /* Sanity check if the interrupt ID is plausible. */ 1752 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest) 1753 || GIC_IS_INTR_SPI(uIntIdHighest) 1754 || GIC_IS_INTR_EXT_PPI(uIntIdHighest) 1755 || GIC_IS_INTR_EXT_SPI(uIntIdHighest) 1756 || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1757 /* Ensure if no interrupt is pending, priority is appropriate. */ 1758 Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 1759 1760 return uIntId; 1761 } 1762 1763 1764 static uint16_t gicReDistGetHighestPrioPendingGroupIntr(PCGICCPU pGicCpu, uint8_t *pbPriority, bool fGroup0) 1765 { 1766 uint32_t bmIntrPending[3]; 1767 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++) 1768 { 1769 bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i]; 1770 if (fGroup0) 1771 bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i]; 1772 else 1773 bmIntrPending[i] &= pGicCpu->bmIntrGroup[i]; 1774 } 1775 1776 void const *pvIntrPending = &bmIntrPending[0]; 1777 uint32_t const cIntrs = sizeof(bmIntrPending) * 8; 1778 uint16_t const uIntId = gicGetHighestPrioPendingIntrFrom(pvIntrPending, cIntrs, pGicCpu->abIntrPriority, 1779 RT_ELEMENTS(pGicCpu->abIntrPriority), pbPriority); 1780 1781 /* Sanity check if the interrupt ID is plausible. */ 1782 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId) 1783 || GIC_IS_INTR_EXT_PPI(uIntId) 1784 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1785 /* Ensure if no interrupt is pending, priority is appropriate. */ 1786 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX); 1787 return uIntId; 1788 } 1789 1790 static uint16_t gicReDistGetHighestPrioPendingIntr(PCGICCPU pGicCpu, uint8_t *pbPriority) 1791 { 1792 uint16_t uIntIdHighest = 0; 1793 uint8_t bPriority = UINT8_MAX; 1794 uint32_t const cIntrs = sizeof(pGicCpu->bmIntrPending) * 8; 1795 void const *pvIntrPending = &pGicCpu->bmIntrPending[0]; 1796 1797 /* Find the INTID and priority of the pending interrupt with the highest priority. */ 1798 int32_t idxIntr = ASMBitFirstSet(pvIntrPending, cIntrs); 1799 AssertCompile(!(cIntrs % 32)); 1800 if (idxIntr >= 0) 1801 { 1802 do 1803 { 1804 uint16_t const uIntId = gicGetIntIdFromIndex((uint16_t)idxIntr); 1805 Assert(uIntId < RT_ELEMENTS(pGicCpu->abIntrPriority)); 1806 if (pGicCpu->abIntrPriority[uIntId] < bPriority) 1807 { 1808 bPriority = pGicCpu->abIntrPriority[idxIntr]; 1809 uIntIdHighest = uIntId; 1810 } 1811 idxIntr = ASMBitNextSet(pvIntrPending, cIntrs, idxIntr); 1812 } while (idxIntr != -1); 1813 } 1814 else 1815 { 1816 bPriority = UINT8_MAX; 1817 uIntIdHighest = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1818 } 1819 1820 /* Sanity check if the interrupt ID is plausible. */ 1821 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest) 1822 || GIC_IS_INTR_EXT_PPI(uIntIdHighest) 1823 || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1824 /* Ensure if no interrupt is pending, priority is appropriate. */ 1825 Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 1826 1827 *pbPriority = bPriority; 1828 return uIntIdHighest; 1829 } 1830 1831 1832 static uint16_t gicGetHighestPrioPendingIntr(PCVMCC pVM, PGICDEV pGicDev) 1833 { 1834 /* Get highest priority pending interrupt from the distributor. */ 1835 uint8_t bPriority; 1836 uint16_t uIntIdHighest = gicDistGetHighestPrioPendingIntr(pGicDev, &bPriority); 1837 1838 /* Compare with the highest priority pending interrupt from each redistributor. */ 1839 uint32_t const cCpus = pVM->cCpus; 1840 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++) 1841 { 1842 PCVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idCpu]; 1843 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1844 1845 uint8_t bReDistPriority; 1846 uint16_t const uIntId = gicReDistGetHighestPrioPendingIntr(pGicCpu, &bReDistPriority); 1847 if ( uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT 1848 && bReDistPriority < bPriority) 1849 { 1850 bReDistPriority = bPriority; 1851 uIntIdHighest = uIntId; 1852 } 1853 } 1854 1855 /* Sanity check if the interrupt ID is plausible. */ 1856 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntIdHighest) 1857 || GIC_IS_INTR_SPI(uIntIdHighest) 1858 || GIC_IS_INTR_EXT_PPI(uIntIdHighest) 1859 || GIC_IS_INTR_EXT_SPI(uIntIdHighest) 1860 || uIntIdHighest == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1861 /* Ensure if no interrupt is pending, priority is appropriate. */ 1862 Assert(uIntIdHighest != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 1863 1864 return uIntIdHighest; 1865 } 1866 #endif 1867 1868 1869 /** 1870 * Gets the highest priority pending distributor interrupt that can be forwarded to 1871 * the redistributor. 1872 * 1873 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt 1874 * is pending or not in a state to be forwarded to the redistributor. 1875 * @param pGicDev The GIC distributor state. 1876 * @param fGroup0 Whether to consider group 0 interrupts. 1877 * @param fGroup1 Whether to consider group 1 interrupts. 1878 * @param pidxIntr Where to store the distributor interrupt index for the 1879 * returned interrupt ID. UINT16_MAX if this function returns 1880 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be 1881 * NULL. 1882 * @param pbPriority Where to store the priority of the returned interrupt ID. 1883 * UINT8_MAX if this function returns 1884 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. 1885 */ 1886 static uint16_t gicDistGetHighestPrioPendingIntr(PCGICDEV pGicDev, bool fGroup0, bool fGroup1, uint16_t *pidxIntr, 1887 uint8_t *pbPriority) 1888 { 1889 /* 1890 * Figure out the highest priority pending interrupt in the distributor. 1891 * We can skip SGIs, PPIs in the distributor as we don't support legacy operation. 1892 * 1893 * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables". 1894 * See ARM GIC spec. 1.3.5 "GICv3 with no legacy operation". 1895 */ 1896 Assert(pGicDev->fAffRoutingEnabled); 1897 uint32_t bmIntrPending[64]; /** @todo SGIs, PPIs: iterate from 1 and initialize bmIntrPending[0] = 0. */ 1898 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrPending); i++) 1899 { 1900 /* Collect interrupts that are pending, enabled and inactive. */ 1901 bmIntrPending[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i]; 1902 1903 /* Discard interrupts if the group they belong to is disabled. */ 1904 if (!fGroup1) 1905 bmIntrPending[i] &= ~pGicDev->bmIntrGroup[i]; 1906 if (!fGroup0) 1907 bmIntrPending[i] &= pGicDev->bmIntrGroup[i]; 1908 } 1909 1910 /* Among the collected interrupts, pick the one with the highest priority. */ 1911 uint16_t uIntId; 1912 uint16_t idxHighest; 1913 uint16_t uPriority = UINT16_MAX; 1914 void const *pvIntrs = &bmIntrPending[0]; 1915 uint32_t const cIntrs = sizeof(bmIntrPending) * 8; 1916 int32_t idxIntr = ASMBitFirstSet(pvIntrs, cIntrs); 1917 AssertCompile(!(cIntrs % 32)); 1918 if (idxIntr >= 0) 1919 { 1920 Assert(idxIntr >= 32); /* We don't support legacy operation. */ 1921 do 1922 { 1923 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority)); 1924 if ((uint16_t)pGicDev->abIntrPriority[idxIntr] < uPriority) 1925 { 1926 idxHighest = (uint16_t)idxIntr; 1927 uPriority = pGicDev->abIntrPriority[idxIntr]; 1928 uIntId = gicDistGetIntIdFromIndex(idxIntr); 1929 } 1930 idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr); 1931 } while (idxIntr != -1); 1932 } 1933 else 1934 { 1935 idxHighest = UINT16_MAX; 1936 uPriority = UINT8_MAX; 1937 uIntId = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1938 } 1939 1940 *pbPriority = uPriority; 1941 if (pidxIntr) 1942 *pidxIntr = idxHighest; 1943 1944 /* Sanity check if the interrupt ID is within known ranges. */ 1945 Assert( GIC_IS_INTR_SPI(uIntId) 1946 || GIC_IS_INTR_EXT_PPI(uIntId) 1947 || GIC_IS_INTR_EXT_SPI(uIntId) 1948 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 1949 /* Ensure that if no interrupt is pending, the priority is appropriate. */ 1950 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX); 1951 1952 LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority)); 1953 return uIntId; 1954 } 1955 1956 1957 /** 1958 * Gets the highest priority pending redistributor interrupt that can be signalled 1959 * to the PE. 1960 * 1961 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt 1962 * is pending or not in a state to be signalled to the PE. 1963 * @param pGicCpu The GIC redistributor and CPU interface state. 1964 * @param fGroup0 Whether to consider group 0 interrupts. 1965 * @param fGroup1 Whether to consider group 1 interrupts. 1966 * @param pidxIntr Where to store the distributor interrupt index for the 1967 * returned interrupt ID. UINT16_MAX if this function returns 1968 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be 1969 * NULL. 1970 * @param pbPriority Where to store the priority of the returned interrupt ID. 1971 * UINT8_MAX if this function returns 1972 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. 1973 */ 1974 static uint16_t gicReDistGetHighestPrioPendingIntr(PCGICCPU pGicCpu, bool fGroup0, bool fGroup1, uint16_t *pidxIntr, 1975 uint8_t *pbPriority) 1976 { 1977 /* 1978 * Figure out the highest priority pending interrupt in the redistributor. 1979 * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables". 1980 */ 1981 uint32_t bmIntrPending[3]; 1982 for (uint8_t i = 0 ; i < RT_ELEMENTS(bmIntrPending); i++) 1983 { 1984 /* Collect interrupts that are pending, enabled and inactive. */ 1985 bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i]; 1986 1987 /* Discard interrupts if the group they belong to is disabled. */ 1988 if (!fGroup1) 1989 bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i]; 1990 if (!fGroup0) 1991 bmIntrPending[i] &= pGicCpu->bmIntrGroup[i]; 1992 } 1993 1994 /* Among the collected interrupts, pick the one with the highest priority. */ 1995 uint16_t uIntId; 1996 uint16_t idxHighest; 1997 uint16_t uPriority = UINT16_MAX; 1998 const void *pvIntrs = &bmIntrPending[0]; 1999 uint32_t const cIntrs = sizeof(bmIntrPending) * 8; 2000 int32_t idxIntr = ASMBitFirstSet(pvIntrs, cIntrs); 2001 AssertCompile(!(cIntrs % 32)); 2002 if (idxIntr >= 0) 2003 { 2004 do 2005 { 2006 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority)); 2007 if ((uint16_t)pGicCpu->abIntrPriority[idxIntr] < uPriority) 2008 { 2009 idxHighest = (uint16_t)idxIntr; 2010 uPriority = pGicCpu->abIntrPriority[idxIntr]; 2011 uIntId = gicReDistGetIntIdFromIndex(idxIntr); 2012 } 2013 idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr); 2014 } while (idxIntr != -1); 2015 } 2016 else 2017 { 2018 idxHighest = UINT16_MAX; 2019 uPriority = UINT8_MAX; 2020 uIntId = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 2021 } 2022 2023 *pbPriority = uPriority; 2024 if (pidxIntr) 2025 *pidxIntr = idxHighest; 2026 2027 /* Sanity check if the interrupt ID is within known ranges. */ 2028 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId) 2029 || GIC_IS_INTR_EXT_PPI(uIntId) 2030 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 2031 /* Ensure that if no interrupt is pending, the priority is appropriate. */ 2032 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX); 2033 2034 LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority)); 2035 return uIntId; 2036 } 2037 2038 2039 /** 2040 * Gets the highest priority pending interrupt that can be signalled to the PE. 2041 * 2042 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt 2043 * is pending or not in a state to be signalled to the PE. 2044 * @param pVM The cross context VM state. 2045 * @param pGicDev The GIC distributor state. 2046 * @param fGroup0 Whether to consider group 0 interrupts. 2047 * @param fGroup1 Whether to consider group 1 interrupts. 2048 */ 2049 static uint16_t gicGetHighestPrioPendingIntr(PCVM pVM, PCGICDEV pGicDev, bool fGroup0, bool fGroup1) 2050 { 2051 /* Get highest priority pending interrupt from the distributor. */ 2052 uint8_t bPriority; 2053 uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, NULL /*pidxIntr*/, &bPriority); 2054 2055 /* Compare with the highest priority pending interrupt from each redistributor. */ 2056 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) 2057 { 2058 PCVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idCpu]; 2059 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 2060 2061 uint8_t bPriorityRedist; 2062 uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, NULL /*pidxIntr*/, 2063 &bPriorityRedist); 2064 if ( uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT 2065 && bPriorityRedist < bPriority) 2066 { 2067 bPriority = bPriorityRedist; 2068 uIntId = uIntIdRedist; 2069 } 2070 } 2071 2072 /* Sanity check if the interrupt ID is within known ranges. */ 2073 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId) 2074 || GIC_IS_INTR_SPI(uIntId) 2075 || GIC_IS_INTR_EXT_PPI(uIntId) 2076 || GIC_IS_INTR_EXT_SPI(uIntId) 2077 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 2078 /* Ensure that if no interrupt is pending, the priority is appropriate. */ 2079 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 2080 2081 LogFlowFunc(("uIntId=%u [bPriority=%u]\n", uIntId, bPriority)); 2082 return uIntId; 2083 } 2084 2085 2086 /** 2087 * Get and acknowledge the interrupt ID of a signalled interrupt. 2088 * 2089 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT no interrupts 2090 * are pending or not in a state to be signalled. 2091 * @param pGicDev The GIC distributor state. 2092 * @param pVCpu The cross context virtual CPU structure. 2093 * @param fGroup0 Whether to consider group 0 interrupts. 2094 * @param fGroup1 Whether to consider group 1 interrupts. 2095 */ 2096 static uint16_t gicAckHighestPrioPendingIntr(PGICDEV pGicDev, PVMCPUCC pVCpu, bool fGroup0, bool fGroup1) 2097 { 2098 Assert(fGroup0 || fGroup1); 2099 LogFlowFunc(("fGroup0=%RTbool fGroup1=%RTbool\n", fGroup0, fGroup1)); 2100 2101 /* Get highest priority pending interrupt from the distributor. */ 2102 uint8_t bPriority; 2103 uint16_t idxIntr; 2104 uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, &idxIntr, &bPriority); 2105 2106 /* Compare with the highest priority pending interrupt from each redistributor. */ 2107 bool fIntrInRedist = false; 2108 uint32_t const cCpus = pVCpu->CTX_SUFF(pVM)->cCpus; 2109 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++) 2110 { 2111 PCVMCPUCC pVCpuCur = pVCpu->CTX_SUFF(pVM)->CTX_SUFF(apCpus)[idCpu]; 2112 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpuCur); 2113 2114 uint8_t bPriorityRedist; 2115 uint16_t idxRedistIntr; 2116 uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, &idxRedistIntr, 2117 &bPriorityRedist); 2118 if ( uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT 2119 && bPriorityRedist < bPriority) 2120 { 2121 fIntrInRedist = true; 2122 bPriority = bPriorityRedist; 2123 uIntId = uIntIdRedist; 2124 idxIntr = idxRedistIntr; 2125 } 2126 } 2127 2128 /* Sanity check if the interrupt ID is within known ranges. */ 2129 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId) 2130 || GIC_IS_INTR_SPI(uIntId) 2131 || GIC_IS_INTR_EXT_PPI(uIntId) 2132 || GIC_IS_INTR_EXT_SPI(uIntId) 2133 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT); 2134 /* Ensure that if no interrupt is pending, the priority is appropriate. */ 2135 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX); 2136 2137 /* Acknowledge the interrupt. */ 2138 if (uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT) 2139 { 2140 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 2141 if (fIntrInRedist) 2142 { 2143 /* Mark the interrupt as active. */ 2144 AssertMsg(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, ("idxIntr=%u\n", idxIntr)); 2145 ASMBitSet(&pGicCpu->bmIntrActive[0], idxIntr); 2146 2147 /* Drop priority. */ 2148 Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1); 2149 2150 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n", 2151 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority], 2152 bPriority, 2153 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1)); 2154 pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority; 2155 2156 /* Clear edge level interrupts like SGIs as pending. */ 2157 /** @todo do this for all edge-triggered? */ 2158 if (idxIntr <= GIC_INTID_RANGE_SGI_LAST) 2159 ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr); 2160 2161 /* Update the redistributor IRQ state to reflect change in active interrupt. */ 2162 gicReDistUpdateIrqState(pGicDev, pVCpu); 2163 } 2164 else 2165 { 2166 /* Mark the interrupt as active. */ 2167 Assert(idxIntr < sizeof(pGicDev->bmIntrActive) * 8); 2168 ASMBitSet(&pGicDev->bmIntrActive[0], idxIntr); 2169 2170 /* Drop priority. */ 2171 Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1); 2172 2173 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n", 2174 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority], 2175 bPriority, 2176 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1)); 2177 pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority; 2178 2179 /* Update the distributor IRQ state to reflect change in active interrupt. */ 2180 gicDistUpdateIrqState(pVCpu->CTX_SUFF(pVM), pGicDev); 2181 } 2182 } 2183 2184 LogFlowFunc(("uIntId=%u\n", uIntId)); 2185 return uIntId; 2186 } 2187 2188 2189 /** 2190 * Reads a distributor register. 378 2191 * 379 2192 * @returns VBox status code. … … 383 2196 * @param puValue Where to store the register value. 384 2197 */ 385 DECLINLINE(VBOXSTRICTRC) gicDistRe gisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)2198 DECLINLINE(VBOXSTRICTRC) gicDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue) 386 2199 { 387 2200 VMCPU_ASSERT_EMT(pVCpu); 388 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 389 390 if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST) 391 { 392 uint32_t idxEntry = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4; 393 if (RT_LIKELY(idxEntry < RT_ELEMENTS(pThis->au32IntRouting))) 394 *puValue = pThis->au32IntRouting[idxEntry]; 395 else 396 *puValue = 0; 397 return VINF_SUCCESS; 2201 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 2202 uint16_t const cbReg = sizeof(uint32_t); 2203 2204 /* 2205 * GICD_IGROUPR<n> and GICD_IGROUPR<n>E. 2206 */ 2207 { 2208 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE) 2209 { 2210 uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg; 2211 return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue); 2212 } 2213 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE) 2214 { 2215 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2; 2216 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg; 2217 return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue); 2218 } 2219 } 2220 2221 /* 2222 * GICD_IROUTER<n> and GICD_IROUTER<n>E. 2223 */ 2224 { 2225 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE) 2226 { 2227 uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg; 2228 return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue); 2229 } 2230 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE) 2231 { 2232 uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2; 2233 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg; 2234 return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue); 2235 } 2236 } 2237 2238 /* 2239 * GICD_ISENABLER<n> and GICD_ISENABLER<n>E. 2240 * GICD_ICENABLER<n> and GICD_ICENABLER<n>E. 2241 */ 2242 { 2243 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE) 2244 { 2245 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg; 2246 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue); 2247 } 2248 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE) 2249 { 2250 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2; 2251 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg; 2252 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue); 2253 } 2254 2255 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE) 2256 { 2257 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg; 2258 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue); 2259 } 2260 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE) 2261 { 2262 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2; 2263 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg; 2264 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue); 2265 } 2266 } 2267 2268 /* 2269 * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E. 2270 * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E. 2271 */ 2272 { 2273 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE) 2274 { 2275 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg; 2276 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue); 2277 } 2278 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE) 2279 { 2280 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2; 2281 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg; 2282 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue); 2283 } 2284 2285 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE) 2286 { 2287 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg; 2288 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue); 2289 } 2290 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE) 2291 { 2292 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2; 2293 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg; 2294 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue); 2295 } 2296 } 2297 2298 /* 2299 * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E. 2300 */ 2301 { 2302 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE) 2303 { 2304 uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg; 2305 return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue); 2306 } 2307 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE) 2308 { 2309 uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t)); 2310 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg; 2311 return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue); 2312 } 2313 } 2314 2315 /* 2316 * GICD_ISPENDR<n> and GICD_ISPENDR<n>E. 2317 * GICD_ICPENDR<n> and GICD_ICPENDR<n>E. 2318 */ 2319 { 2320 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE) 2321 { 2322 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg; 2323 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue); 2324 } 2325 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE) 2326 { 2327 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2; 2328 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg; 2329 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue); 2330 } 2331 2332 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE) 2333 { 2334 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg; 2335 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue); 2336 } 2337 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE) 2338 { 2339 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2; 2340 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg; 2341 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue); 2342 } 2343 } 2344 2345 /* 2346 * GICD_ICFGR<n> and GICD_ICFGR<n>E. 2347 */ 2348 { 2349 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START < GIC_DIST_REG_ICFGRn_RANGE_SIZE) 2350 { 2351 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg; 2352 return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue); 2353 } 2354 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE) 2355 { 2356 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2; 2357 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg; 2358 return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue); 2359 } 398 2360 } 399 2361 … … 401 2363 { 402 2364 case GIC_DIST_REG_CTLR_OFF: 403 *puValue = (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0) 404 | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0) 405 | GIC_DIST_REG_CTRL_DS 406 | GIC_DIST_REG_CTRL_ARE_S; 2365 Assert(pGicDev->fAffRoutingEnabled); /* We don't support GICv2 backwards compatibility, so ARE bit must be set. */ 2366 *puValue = (pGicDev->fIrqGrp0Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0) 2367 | (pGicDev->fIrqGrp1Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0) 2368 | GIC_DIST_REG_CTRL_DS 2369 | (pGicDev->fAffRoutingEnabled ? GIC_DIST_REG_CTRL_ARE_S : 0); 407 2370 break; 408 2371 case GIC_DIST_REG_TYPER_OFF: 409 Assert(pThis->uMaxSpi > 0 && pThis->uMaxSpi < GIC_DIST_REG_TYPER_NUM_ITLINES); 410 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(pThis->uMaxSpi) 411 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */ /** @todo r=ramshankar: Should this be pVCpu->cCpus? Currently it means 'ARE' must always be used? */ 412 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */ 413 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */ 414 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */ 415 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */ 416 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */ 417 | GIC_DIST_REG_TYPER_IDBITS_SET(16); 2372 Assert(pGicDev->uMaxSpi > 0 && pGicDev->uMaxSpi < GIC_DIST_REG_TYPER_NUM_ITLINES); 2373 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(pGicDev->uMaxSpi) 2374 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */ /** @todo r=ramshankar: Should this be pVCpu->cCpus? Currently it means 'ARE' must always be used? */ 2375 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */ 2376 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */ 2377 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */ 2378 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */ 2379 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */ 2380 | (pGicDev->fRangeSelSupport ? GIC_DIST_REG_TYPER_RSS : 0) 2381 | GIC_DIST_REG_TYPER_IDBITS_SET(16); 418 2382 break; 419 2383 case GIC_DIST_REG_STATUSR_OFF: 420 2384 AssertReleaseFailed(); 421 2385 break; 2386 #if 0 422 2387 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */ 423 2388 AssertReleaseFailed(); … … 427 2392 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled); 428 2393 break; 2394 #endif 429 2395 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */ 430 2396 AssertReleaseFailed(); … … 439 2405 AssertReleaseFailed(); 440 2406 break; 2407 #if 0 441 2408 case GIC_DIST_REG_IPRIORITYRn_OFF_START: 442 2409 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 4: /* These are banked for the PEs and access the redistributor. */ … … 468 2435 break; 469 2436 } 2437 #endif 470 2438 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */ 471 2439 AssertReleaseFailed(); … … 493 2461 break; 494 2462 case GIC_DIST_REG_PIDR2_OFF: 2463 #if 0 495 2464 Assert(pThis->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4); 496 2465 *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pThis->uArchRev); 2466 #else 2467 Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4); 2468 *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev); 2469 #endif 497 2470 break; 498 2471 case GIC_DIST_REG_IIDR_OFF: 2472 *puValue = 0x43b; /* JEP106 code 0x43b is an ARM implementation. */ 2473 break; 499 2474 case GIC_DIST_REG_TYPER2_OFF: 500 2475 *puValue = 0; 501 2476 break; 2477 #if 0 502 2478 case GIC_DIST_REG_IROUTERn_OFF_START: 503 2479 AssertFailed(); 504 2480 break; 2481 #endif 505 2482 default: 506 2483 *puValue = 0; … … 511 2488 512 2489 /** 513 * Writes a GICdistributor register.2490 * Writes a distributor register. 514 2491 * 515 2492 * @returns Strict VBox status code. … … 519 2496 * @param uValue The register value. 520 2497 */ 521 DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue) 522 { 523 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu); 524 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 525 PVMCC pVM = PDMDevHlpGetVM(pDevIns); 526 527 if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST) 528 { 529 uint32_t idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4; 530 LogFlowFunc(("GicDist: idxIRouter=%u uValue=%#x\n", idxReg, uValue)); 531 if (idxReg < RT_ELEMENTS(pThis->au32IntRouting)) 532 pThis->au32IntRouting[idxReg] = uValue; 533 return VINF_SUCCESS; 2498 DECLINLINE(VBOXSTRICTRC) gicDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue) 2499 { 2500 VMCPU_ASSERT_EMT(pVCpu); 2501 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 2502 PVMCC pVM = PDMDevHlpGetVM(pDevIns); 2503 uint16_t const cbReg = sizeof(uint32_t); 2504 2505 /* 2506 * GICD_IGROUPR<n> and GICD_IGROUPR<n>E. 2507 */ 2508 { 2509 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE) 2510 { 2511 uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg; 2512 return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue); 2513 } 2514 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE) 2515 { 2516 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2; 2517 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg; 2518 return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue); 2519 } 2520 } 2521 2522 /* 2523 * GICD_IROUTER<n> and GICD_IROUTER<n>E. 2524 */ 2525 { 2526 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE) 2527 { 2528 uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg; 2529 return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue); 2530 } 2531 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE) 2532 { 2533 uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2; 2534 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg; 2535 return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue); 2536 } 2537 } 2538 2539 /* 2540 * GICD_ISENABLER<n> and GICD_ISENABLER<n>E. 2541 * GICD_ICENABLER<n> and GICD_ICENABLER<n>E. 2542 */ 2543 { 2544 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE) 2545 { 2546 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg; 2547 return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue); 2548 } 2549 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE) 2550 { 2551 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2; 2552 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg; 2553 return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue); 2554 } 2555 2556 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE) 2557 { 2558 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg; 2559 return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue); 2560 } 2561 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE) 2562 { 2563 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2; 2564 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg; 2565 return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue); 2566 } 2567 } 2568 2569 /* 2570 * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E. 2571 * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E. 2572 */ 2573 { 2574 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE) 2575 { 2576 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg; 2577 return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue); 2578 } 2579 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE) 2580 { 2581 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2; 2582 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg; 2583 return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue); 2584 } 2585 2586 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE) 2587 { 2588 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START) / cbReg; 2589 return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue); 2590 } 2591 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE) 2592 { 2593 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2; 2594 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg; 2595 return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue); 2596 } 2597 } 2598 2599 /* 2600 * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E. 2601 */ 2602 { 2603 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE) 2604 { 2605 uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg; 2606 return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue); 2607 } 2608 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE) 2609 { 2610 uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t)); 2611 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg; 2612 return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue); 2613 } 2614 } 2615 2616 /* 2617 * GICD_ISPENDR<n> and GICD_ISPENDR<n>E. 2618 * GICD_ICPENDR<n> and GICD_ICPENDR<n>E. 2619 */ 2620 { 2621 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE) 2622 { 2623 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg; 2624 return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue); 2625 } 2626 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE) 2627 { 2628 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2; 2629 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg; 2630 return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue); 2631 } 2632 2633 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE) 2634 { 2635 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg; 2636 return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue); 2637 } 2638 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE) 2639 { 2640 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2; 2641 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg; 2642 return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue); 2643 } 2644 } 2645 2646 /* 2647 * GICD_ICFGR<n> and GICD_ICFGR<n>E. 2648 */ 2649 { 2650 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START + cbReg < GIC_DIST_REG_ICFGRn_RANGE_SIZE) 2651 { 2652 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg; 2653 return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue); 2654 } 2655 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE) 2656 { 2657 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2; 2658 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg; 2659 return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue); 2660 } 534 2661 } 535 2662 … … 538 2665 { 539 2666 case GIC_DIST_REG_CTLR_OFF: 2667 #if 0 540 2668 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0)); 541 2669 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS)); 542 2670 Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS)); 543 2671 rcStrict = gicDistUpdateIrqState(pVM, pThis); 2672 #else 2673 Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS)); 2674 pGicDev->fIrqGrp0Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0); 2675 pGicDev->fIrqGrp1Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS); 2676 rcStrict = gicDistUpdateIrqState(pVM, pGicDev); 2677 #endif 544 2678 break; 545 2679 case GIC_DIST_REG_STATUSR_OFF: … … 558 2692 AssertReleaseFailed(); 559 2693 break; 2694 #if 0 560 2695 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */ 561 2696 AssertReleaseFailed(); … … 641 2776 break; 642 2777 } 2778 #endif 643 2779 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */ 644 2780 AssertReleaseFailed(); 645 2781 break; 2782 #if 0 646 2783 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */ 647 2784 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue); … … 650 2787 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue); 651 2788 break; 2789 #endif 652 2790 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */ 653 2791 AssertReleaseFailed(); … … 687 2825 * @param puValue Where to store the register value. 688 2826 */ 689 DECLINLINE(VBOXSTRICTRC) gicReDistRe gisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)690 { 691 PGICDEV p This= PDMDEVINS_2_DATA(pDevIns, PGICDEV);692 2827 DECLINLINE(VBOXSTRICTRC) gicReDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue) 2828 { 2829 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 2830 Assert(idRedist == pVCpu->idCpu); /* Assert for now, maybe remove function parameter later. */ 693 2831 switch (offReg) 694 2832 { 695 2833 case GIC_REDIST_REG_TYPER_OFF: 696 2834 { 697 PVMCC pVM = PDMDevHlpGetVM(pDevIns); 698 *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0) 699 | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist) 700 | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL); 701 break; 702 } 2835 PCVMCC pVM = PDMDevHlpGetVM(pDevIns); 2836 *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0) 2837 | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist) 2838 | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL); 2839 break; 2840 } 2841 case GIC_REDIST_REG_IIDR_OFF: 2842 *puValue = 0x43b; /* JEP106 code 0x43b is an ARM implementation. */ 2843 break; 703 2844 case GIC_REDIST_REG_TYPER_AFFINITY_OFF: 704 2845 *puValue = idRedist; 705 2846 break; 706 2847 case GIC_REDIST_REG_PIDR2_OFF: 707 Assert(p This->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);708 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(p This->uArchRev);2848 Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4); 2849 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev); 709 2850 break; 710 2851 default: 711 2852 *puValue = 0; 712 2853 } 713 714 2854 return VINF_SUCCESS; 715 2855 } … … 725 2865 * @param puValue Where to store the register value. 726 2866 */ 727 DECLINLINE(VBOXSTRICTRC) gicReDist SgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)2867 DECLINLINE(VBOXSTRICTRC) gicReDistReadSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue) 728 2868 { 729 2869 VMCPU_ASSERT_EMT(pVCpu); 730 2870 RT_NOREF(pDevIns); 731 2871 732 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu); 2872 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 2873 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 2874 uint16_t const cbReg = sizeof(uint32_t); 2875 2876 #if 1 2877 /* 2878 * GICR_IGROUPR0 and GICR_IGROUPR<n>E. 2879 */ 2880 { 2881 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE) 2882 { 2883 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg; 2884 return gicReDistReadIntrGroupReg(pGicDev, pGicCpu, idxReg, puValue); 2885 } 2886 } 2887 2888 /* 2889 * GICR_ISENABLER0 and GICR_ISENABLER<n>E. 2890 * GICR_ICENABLER0 and GICR_ICENABLER<n>E. 2891 */ 2892 { 2893 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE) 2894 { 2895 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg; 2896 return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue); 2897 } 2898 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE) 2899 { 2900 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLERnE_OFF_START) / cbReg; 2901 return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue); 2902 } 2903 } 2904 2905 /* 2906 * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E. 2907 * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E. 2908 */ 2909 { 2910 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE) 2911 { 2912 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg; 2913 return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue); 2914 } 2915 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE) 2916 { 2917 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg; 2918 return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue); 2919 } 2920 } 2921 2922 /* 2923 * GICR_ISPENDR0 and GICR_ISPENDR<n>E. 2924 * GICR_ICPENDR0 and GICR_ICPENDR<n>E. 2925 */ 2926 { 2927 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE) 2928 { 2929 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg; 2930 return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue); 2931 } 2932 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE) 2933 { 2934 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg; 2935 return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue); 2936 } 2937 } 2938 2939 /* 2940 * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E. 2941 */ 2942 { 2943 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE) 2944 { 2945 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg; 2946 return gicReDistReadIntrPriorityReg(pGicDev, pGicCpu, idxReg, puValue); 2947 } 2948 } 2949 2950 /* 2951 * GICR_ICFGR0, GICR_ICFGR1 and GICR_ICFGR<n>E. 2952 */ 2953 { 2954 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE) 2955 { 2956 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg; 2957 return gicReDistReadIntrConfigReg(pGicDev, pGicCpu, idxReg, puValue); 2958 } 2959 } 2960 2961 AssertReleaseFailed(); 2962 *puValue = 0; 2963 return VINF_SUCCESS; 2964 #else 733 2965 switch (offReg) 734 2966 { … … 777 3009 778 3010 return VINF_SUCCESS; 3011 #endif 779 3012 } 780 3013 … … 789 3022 * @param uValue The register value. 790 3023 */ 791 DECLINLINE(VBOXSTRICTRC) gicReDist RegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)3024 DECLINLINE(VBOXSTRICTRC) gicReDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue) 792 3025 { 793 3026 VMCPU_ASSERT_EMT(pVCpu); … … 842 3075 * @param uValue The register value. 843 3076 */ 844 DECLINLINE(VBOXSTRICTRC) gicReDist SgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)3077 DECLINLINE(VBOXSTRICTRC) gicReDistWriteSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue) 845 3078 { 846 3079 VMCPU_ASSERT_EMT(pVCpu); 847 RT_NOREF(pDevIns); 848 849 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu); 3080 3081 #if 1 3082 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV); 3083 3084 /* 3085 * GICR_IGROUPR0 and GICR_IGROUPR<n>E. 3086 */ 3087 { 3088 uint16_t const cbReg = sizeof(uint32_t); 3089 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE) 3090 { 3091 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg; 3092 return gicReDistWriteIntrGroupReg(pGicDev, pVCpu, idxReg, uValue); 3093 } 3094 } 3095 3096 /* 3097 * GICR_ISENABLER0 and GICR_ISENABLER<n>E. 3098 * GICR_ICENABLER0 and GICR_ICENABLER<n>E. 3099 */ 3100 { 3101 uint16_t const cbReg = sizeof(uint32_t); 3102 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE) 3103 { 3104 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg; 3105 return gicReDistWriteIntrSetEnableReg(pGicDev, pVCpu, idxReg, uValue); 3106 } 3107 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE) 3108 { 3109 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF) / cbReg; 3110 return gicReDistWriteIntrClearEnableReg(pGicDev, pVCpu, idxReg, uValue); 3111 } 3112 } 3113 3114 /* 3115 * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E. 3116 * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E. 3117 */ 3118 { 3119 uint16_t const cbReg = sizeof(uint32_t); 3120 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE) 3121 { 3122 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg; 3123 return gicReDistWriteIntrSetActiveReg(pGicDev, pVCpu, idxReg, uValue); 3124 } 3125 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE) 3126 { 3127 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg; 3128 return gicReDistWriteIntrClearActiveReg(pGicDev, pVCpu, idxReg, uValue); 3129 } 3130 } 3131 3132 /* 3133 * GICR_ISPENDR0 and GICR_ISPENDR<n>E. 3134 * GICR_ICPENDR0 and GICR_ICPENDR<n>E. 3135 */ 3136 { 3137 uint16_t const cbReg = sizeof(uint32_t); 3138 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE) 3139 { 3140 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg; 3141 return gicReDistWriteIntrSetPendingReg(pGicDev, pVCpu, idxReg, uValue); 3142 } 3143 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE) 3144 { 3145 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg; 3146 return gicReDistWriteIntrClearPendingReg(pGicDev, pVCpu, idxReg, uValue); 3147 } 3148 } 3149 3150 /* 3151 * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E. 3152 */ 3153 { 3154 uint16_t const cbReg = sizeof(uint32_t); 3155 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE) 3156 { 3157 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg; 3158 return gicReDistWriteIntrPriorityReg(pGicDev, pVCpu, idxReg, uValue); 3159 } 3160 } 3161 3162 /* 3163 * GICR_ICFGR0, GIC_ICFGR1 and GICR_ICFGR<n>E. 3164 */ 3165 { 3166 uint16_t const cbReg = sizeof(uint32_t); 3167 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE) 3168 { 3169 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg; 3170 return gicReDistWriteIntrConfigReg(pGicDev, pVCpu, idxReg, uValue); 3171 } 3172 } 3173 3174 AssertReleaseFailed(); 3175 return VERR_INTERNAL_ERROR_2; 3176 #else 850 3177 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 851 3178 switch (offReg) … … 908 3235 break; 909 3236 } 910 911 3237 return rcStrict; 3238 #endif 912 3239 } 913 3240 … … 916 3243 * @interface_method_impl{PDMGICBACKEND,pfnSetSpi} 917 3244 */ 918 static DECLCALLBACK(int) gicSetSpi(PVMCC pVM, uint32_t uIntId, bool fAsserted) 919 { 920 LogFlowFunc(("pVM=%p uIntId=%u fAsserted=%RTbool\n", 921 pVM, uIntId, fAsserted)); 922 923 AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER); 3245 static DECLCALLBACK(int) gicSetSpi(PVMCC pVM, uint32_t uSpiIntId, bool fAsserted) 3246 { 3247 LogFlowFunc(("pVM=%p uSpiIntId=%u fAsserted=%RTbool\n", 3248 pVM, uSpiIntId, fAsserted)); 924 3249 925 3250 PGIC pGic = VM_TO_GIC(pVM); 926 3251 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns); 927 PGICDEV p This= PDMDEVINS_2_DATA(pDevIns, PGICDEV);3252 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 928 3253 929 3254 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 930 3255 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 931 3256 3257 #if 0 932 3258 /* Update the interrupts pending state. */ 933 3259 if (fAsserted) … … 937 3263 938 3264 int rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis)); 3265 #else 3266 uint16_t const uIntId = GIC_INTID_RANGE_SPI_START + uSpiIntId; 3267 uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId); 3268 3269 Assert(idxIntr >= GIC_INTID_RANGE_SPI_START); 3270 AssertMsgReturnStmt(idxIntr < sizeof(pGicDev->bmIntrPending) * 8, 3271 ("out-of-range SPI interrupt ID %RU32 (%RU32)\n", uIntId, uSpiIntId), 3272 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3), 3273 VERR_INVALID_PARAMETER); 3274 3275 /* Update the interrupt pending state. */ 3276 if (fAsserted) 3277 ASMBitSet(&pGicDev->bmIntrPending[0], idxIntr); 3278 else 3279 ASMBitClear(&pGicDev->bmIntrPending[0], idxIntr); 3280 int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev)); 3281 #endif 3282 939 3283 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 940 3284 return rc; … … 945 3289 * @interface_method_impl{PDMGICBACKEND,pfnSetPpi} 946 3290 */ 947 static DECLCALLBACK(int) gicSetPpi(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted) 948 { 3291 static DECLCALLBACK(int) gicSetPpi(PVMCPUCC pVCpu, uint32_t uPpiIntId, bool fAsserted) 3292 { 3293 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uPpiIntId=%u fAsserted=%RTbool\n", pVCpu, pVCpu->idCpu, uPpiIntId, fAsserted)); 3294 3295 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu); 3296 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV); 3297 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 3298 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 3299 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 3300 3301 #if 0 3302 AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER); 3303 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted); 3304 #else 3305 uint32_t const uIntId = GIC_INTID_RANGE_PPI_START + uPpiIntId; 3306 uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId); 3307 3308 Assert(idxIntr >= GIC_INTID_RANGE_PPI_START); 3309 AssertMsgReturnStmt(idxIntr < sizeof(pGicCpu->bmIntrPending) * 8, 3310 ("out-of-range PPI interrupt ID %RU32 (%RU32)\n", uIntId, uPpiIntId), 3311 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3), 3312 VERR_INVALID_PARAMETER); 3313 3314 /* Update the interrupt pending state. */ 3315 if (fAsserted) 3316 ASMBitSet(&pGicCpu->bmIntrPending[0], idxIntr); 3317 else 3318 ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr); 3319 int const rc = VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pGicDev, pVCpu)); 3320 #endif 3321 3322 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 3323 3324 return rc; 3325 } 3326 3327 3328 /** 3329 * Sets the specified software generated interrupt (SGI). 3330 * 3331 * @returns VBox status code. 3332 * @param pVM The cross context VM structure. 3333 * @param pVCpu The cross context virtual CPU structure. 3334 * @param pDestCpuSet Which CPUs to deliver the SGI to. 3335 * @param uIntId The SGI interrupt ID. 3336 */ 3337 static int gicSetSgi(PCGICDEV pGicDev, PVMCPUCC pVCpu, PCVMCPUSET pDestCpuSet, uint8_t uIntId) 3338 { 3339 #if 0 949 3340 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n", 950 3341 pVCpu, pVCpu->idCpu, uIntId, fAsserted)); … … 954 3345 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 955 3346 956 AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);957 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);958 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);959 960 return rc;961 }962 963 964 /**965 * Sets the specified software generated interrupt starting.966 *967 * @returns VBox status code.968 * @param pVCpu The cross context virtual CPU structure.969 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.970 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.971 */972 static int gicSetSgi(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)973 {974 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",975 pVCpu, pVCpu->idCpu, uIntId, fAsserted));976 977 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);978 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);979 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);980 981 3347 AssertReturn(uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER); 982 3348 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted); 983 3349 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 984 3350 #else 3351 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u\n", pVCpu, pVCpu->idCpu, uIntId)); 3352 3353 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu); 3354 PCVMCC pVM = pVCpu->CTX_SUFF(pVM); 3355 uint32_t const cCpus = pVM->cCpus; 3356 AssertReturn(uIntId <= GIC_INTID_RANGE_SGI_LAST, VERR_INVALID_PARAMETER); 3357 3358 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 3359 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 3360 3361 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++) 3362 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu)) 3363 { 3364 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->CTX_SUFF(apCpus)[idCpu]); 3365 pGicCpu->bmIntrPending[0] |= RT_BIT_32(uIntId); 3366 } 3367 3368 int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev)); 3369 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 3370 #endif 985 3371 return rc; 3372 } 3373 3374 3375 /** 3376 * Writes to the redistributor's SGI group 1 register (ICC_SGI1R_EL1). 3377 * 3378 * @returns Strict VBox status code. 3379 * @param pGicDev The GIC distributor state. 3380 * @param pVCpu The cross context virtual CPU structure. 3381 * @param uValue The value being written to the ICC_SGI1R_EL1 register. 3382 */ 3383 static VBOXSTRICTRC gicReDistWriteSgiReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint64_t uValue) 3384 { 3385 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 3386 VMCPUSET DestCpuSet; 3387 if (uValue & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM) 3388 { 3389 /* 3390 * Deliver to all VCPUs but this one. 3391 */ 3392 VMCPUSET_FILL(&DestCpuSet); 3393 VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu); 3394 } 3395 else 3396 { 3397 /* 3398 * Target specific VCPUs. 3399 * See ARM GICv3 and GICv4 Software Overview spec 3.3 "Affinity routing". 3400 */ 3401 VMCPUSET_EMPTY(&DestCpuSet); 3402 bool const fRangeSelSupport = RT_BOOL(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_RSS); 3403 uint8_t const idRangeStart = ARMV8_ICC_SGI1R_EL1_AARCH64_RS_GET(uValue) * 16; 3404 uint16_t const bmCpuInterfaces = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(uValue); 3405 uint8_t const uAff1 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF1_GET(uValue); 3406 uint8_t const uAff2 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF2_GET(uValue); 3407 uint8_t const uAff3 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF3_GET(uValue); 3408 uint32_t const cCpus = pVCpu->CTX_SUFF(pVM)->cCpus; 3409 for (uint8_t idCpuInterface = 0; idCpuInterface < 16; idCpuInterface++) 3410 { 3411 if (bmCpuInterfaces & RT_BIT(idCpuInterface)) 3412 { 3413 VMCPUID idCpuTarget; 3414 if (fRangeSelSupport) 3415 idCpuTarget = RT_MAKE_U32_FROM_U8(idRangeStart + idCpuInterface, uAff1, uAff2, uAff3); 3416 else 3417 idCpuTarget = gicGetCpuIdFromAffinity(idCpuInterface, uAff1, uAff2, uAff3); 3418 if (RT_LIKELY(idCpuTarget < cCpus)) 3419 VMCPUSET_ADD(&DestCpuSet, idCpuTarget); 3420 else 3421 AssertReleaseFailed(); 3422 } 3423 } 3424 } 3425 3426 if (!VMCPUSET_IS_EMPTY(&DestCpuSet)) 3427 { 3428 uint8_t const uSgiIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(uValue); 3429 Assert(GIC_IS_INTR_SGI(uSgiIntId)); 3430 #if 0 3431 uint16_t const idxIdb = uSgiIntId; 3432 gicPostInterrupt(pVCpu, &DestCpuSet, idxIdb); 3433 #else 3434 gicSetSgi(pGicDev, pVCpu, &DestCpuSet, uSgiIntId); 3435 #endif 3436 } 3437 return VINF_SUCCESS; 986 3438 } 987 3439 … … 999 3451 1000 3452 *pu64Value = 0; 1001 PGICCPU pThis= VMCPU_TO_GICCPU(pVCpu);3453 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1002 3454 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu); 1003 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);3455 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 1004 3456 1005 3457 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); … … 1009 3461 { 1010 3462 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1: 1011 *pu64Value = p This->bInterruptPriority;3463 *pu64Value = pGicCpu->bInterruptPriority; 1012 3464 break; 1013 3465 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1: … … 1021 3473 break; 1022 3474 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1: 1023 *pu64Value = pThis->bBinaryPointGrp0 & 0x7;3475 *pu64Value = ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp0); 1024 3476 break; 1025 3477 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1: … … 1054 3506 break; 1055 3507 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1: 1056 *pu64Value = p This->abRunningPriorities[pThis->idxRunningPriority];3508 *pu64Value = pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]; 1057 3509 break; 1058 3510 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1: … … 1067 3519 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1: 1068 3520 { 3521 #if 0 1069 3522 /** @todo Figure out the highest priority interrupt. */ 1070 3523 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive); … … 1123 3576 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1124 3577 } 3578 #else 3579 *pu64Value = gicAckHighestPrioPendingIntr(pGicDev, pVCpu, false /*fGroup0*/, true /*fGroup1*/); 3580 #endif 1125 3581 break; 1126 3582 } … … 1130 3586 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1: 1131 3587 { 3588 #if 0 1132 3589 /** @todo Figure out the highest priority interrupt. */ 1133 3590 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive); … … 1149 3606 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT; 1150 3607 } 3608 #else 3609 AssertReleaseFailed(); 3610 *pu64Value = gicGetHighestPrioPendingIntr(pVCpu->pVMR3, pGicDev, false /*fGroup0*/, true /*fGroup1*/); 3611 #endif 1151 3612 break; 1152 3613 } 1153 3614 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1: 1154 *pu64Value = ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_SET(p This->bBinaryPointGrp1);3615 *pu64Value = ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp1); 1155 3616 break; 1156 3617 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1: 1157 *pu64Value = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE 1158 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4) 1159 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS); 3618 *pu64Value = pGicCpu->uIccCtlr; 1160 3619 break; 1161 3620 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1: … … 1163 3622 break; 1164 3623 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1: 1165 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled)? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;3624 *pu64Value = pGicCpu->fIrqGrp0Enabled ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0; 1166 3625 break; 1167 3626 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1: 1168 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled)? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;3627 *pu64Value = pGicCpu->fIrqGrp1Enabled ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0; 1169 3628 break; 1170 3629 default: … … 1175 3634 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 1176 3635 1177 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIcc RegisterStringify(u32Reg), *pu64Value));3636 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), *pu64Value)); 1178 3637 return VINF_SUCCESS; 1179 3638 } … … 1189 3648 */ 1190 3649 VMCPU_ASSERT_EMT(pVCpu); 1191 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), u64Value)); 1192 1193 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu); 3650 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), u64Value)); 3651 1194 3652 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu); 1195 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 3653 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 3654 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu); 1196 3655 1197 3656 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED); 1198 3657 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); 1199 3658 3659 VBOXSTRICTRC rcStrict = VINF_SUCCESS; 1200 3660 switch (u32Reg) 1201 3661 { 1202 3662 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1: 1203 3663 LogFlowFunc(("ICC_PMR_EL1: Interrupt priority now %u\n", (uint8_t)u64Value)); 3664 #if 0 1204 3665 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value); 1205 3666 gicReDistUpdateIrqState(pThis, pVCpu); 3667 #else 3668 pGicCpu->bInterruptPriority = (uint8_t)u64Value; 3669 rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu); 3670 #endif 1206 3671 break; 1207 3672 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1: … … 1215 3680 break; 1216 3681 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1: 3682 #if 0 1217 3683 pThis->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value); 3684 #else 3685 pGicCpu->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value); 3686 #endif 1218 3687 break; 1219 3688 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1: … … 1252 3721 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1: 1253 3722 { 3723 #if 0 1254 3724 uint32_t uIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(u64Value) - GIC_INTID_RANGE_SGI_START; 1255 3725 if (u64Value & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM) … … 1289 3759 } 1290 3760 } 3761 #else 3762 gicReDistWriteSgiReg(pGicDev, pVCpu, u64Value); 3763 #endif 1291 3764 break; 1292 3765 } … … 1302 3775 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1: 1303 3776 { 3777 #if 0 1304 3778 /* Mark the interrupt as not active anymore, though it might still be pending. */ 1305 3779 if (u64Value < GIC_INTID_RANGE_SPI_START) … … 1319 3793 } 1320 3794 gicReDistUpdateIrqState(pThis, pVCpu); 3795 #else 3796 /* 3797 * We only support priority drop + interrupt deactivation with writes to this register. 3798 * This avoids an extra access which would be required by software for deactivation. 3799 */ 3800 Assert(!(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_EOIMODE)); 3801 3802 /* 3803 * Mark the interrupt as inactive, though it might still be pending. 3804 * WARNING! The order of the 'if' checks below are crucial. 3805 */ 3806 uint16_t const uIntId = (uint16_t)u64Value; 3807 if (uIntId <= GIC_INTID_RANGE_PPI_LAST) 3808 { 3809 /* SGIs and PPIs. */ 3810 AssertCompile(GIC_INTID_RANGE_PPI_LAST < 8 * sizeof(pGicDev->bmIntrActive[0])); 3811 Assert(pGicDev->fAffRoutingEnabled); 3812 pGicCpu->bmIntrActive[0] &= ~RT_BIT_32(uIntId); 3813 } 3814 else if (uIntId <= GIC_INTID_RANGE_SPI_LAST) 3815 { 3816 /* SPIs. */ 3817 uint16_t const idxIntr = /*gicDistGetIndexFromIntId*/(uIntId); 3818 AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW); 3819 ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr); 3820 } 3821 else if (uIntId <= GIC_INTID_RANGE_EXT_PPI_LAST) 3822 { 3823 /* Extended PPIs. */ 3824 uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId); 3825 AssertReturn(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW); 3826 ASMBitClear(&pGicCpu->bmIntrActive[0], idxIntr); 3827 } 3828 else if (uIntId <= GIC_INTID_RANGE_EXT_SPI_LAST) 3829 { 3830 /* Extended SPIs. */ 3831 uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId); 3832 AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW); 3833 ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr); 3834 } 3835 else 3836 { 3837 AssertMsgFailed(("Invalid INTID %u\n", uIntId)); 3838 break; 3839 } 3840 3841 /* 3842 * Restore previous interrupt priority. 3843 */ 3844 Assert(pGicCpu->idxRunningPriority > 0); 3845 if (RT_LIKELY(pGicCpu->idxRunningPriority)) 3846 { 3847 LogFlowFunc(("Restoring interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n", 3848 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority], 3849 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority - 1], 3850 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority - 1)); 3851 pGicCpu->idxRunningPriority--; 3852 } 3853 rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu); 3854 #endif 1321 3855 break; 1322 3856 } … … 1325 3859 break; 1326 3860 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1: 1327 p This->bBinaryPointGrp1 = (uint8_t)ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_GET(u64Value);3861 pGicCpu->bBinaryPointGrp1 = (uint8_t)ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_GET(u64Value); 1328 3862 break; 1329 3863 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1: 1330 u64Value&= ARMV8_ICC_CTLR_EL1_RW;3864 pGicCpu->uIccCtlr &= ARMV8_ICC_CTLR_EL1_RW; 1331 3865 /** @todo */ 1332 3866 break; … … 1335 3869 break; 1336 3870 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1: 1337 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));3871 pGicCpu->fIrqGrp0Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE); 1338 3872 break; 1339 3873 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1: 1340 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));3874 pGicCpu->fIrqGrp1Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE); 1341 3875 break; 1342 3876 default: … … 1346 3880 1347 3881 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3); 1348 return VINF_SUCCESS; 3882 return rcStrict; 3883 } 3884 3885 3886 /** 3887 * Initializes the GIC distributor state. 3888 * 3889 * @param pDevIns The device instance. 3890 */ 3891 DECLHIDDEN(void) gicInit(PPDMDEVINS pDevIns) 3892 { 3893 LogFlowFunc(("\n")); 3894 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 3895 RT_ZERO(pGicDev->bmIntrGroup); 3896 RT_ZERO(pGicDev->bmIntrConfig); 3897 RT_ZERO(pGicDev->bmIntrEnabled); 3898 RT_ZERO(pGicDev->bmIntrPending); 3899 RT_ZERO(pGicDev->bmIntrActive); 3900 RT_ZERO(pGicDev->abIntrPriority); 3901 RT_ZERO(pGicDev->au32IntrRouting); 3902 RT_ZERO(pGicDev->bmIntrRoutingMode); 3903 pGicDev->fIrqGrp0Enabled = false; 3904 pGicDev->fIrqGrp1Enabled = false; 3905 pGicDev->fAffRoutingEnabled = true; /* GICv2 backwards compatibility is not implemented, so this is RA1/WI. */ 3906 } 3907 3908 3909 /** 3910 * Initialies the GIC redistributor and CPU interface state. 3911 * 3912 * @param pDevIns The device instance. 3913 * @param pVCpu The cross context virtual CPU structure. 3914 */ 3915 DECLHIDDEN(void) gicInitCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu) 3916 { 3917 LogFlowFunc(("[%u]\n", pVCpu->idCpu)); 3918 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV); 3919 PGICCPU pGicCpu = &pVCpu->gic.s; 3920 RT_ZERO(pGicCpu->bmIntrGroup); 3921 RT_ZERO(pGicCpu->bmIntrConfig); 3922 RT_ZERO(pGicCpu->bmIntrEnabled); 3923 RT_ZERO(pGicCpu->bmIntrPending); 3924 RT_ZERO(pGicCpu->bmIntrActive); 3925 RT_ZERO(pGicCpu->abIntrPriority); 3926 pGicCpu->fRegWritePending = false; 3927 3928 /* SGIs are always edge-triggered, writes to GICR_ICFGR0 are to be ignored. */ 3929 pGicCpu->bmIntrConfig[0] = 0xaaaaaaaa; 3930 3931 pGicCpu->uIccCtlr = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE 3932 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4) 3933 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS) 3934 | (pGicDev->fRangeSelSupport ? ARMV8_ICC_CTLR_EL1_AARCH64_RSS : 0); 3935 3936 memset((void *)&pGicCpu->abRunningPriorities[0], 0xff, sizeof(pGicCpu->abRunningPriorities)); 3937 pGicCpu->idxRunningPriority = 0; 3938 pGicCpu->bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */ 3939 pGicCpu->fIrqGrp0Enabled = false; 3940 pGicCpu->fIrqGrp1Enabled = false; 3941 3942 /* The binary point register are undefined on reset, initialized 3943 with arbitrarily chosen values in our implementation. */ 3944 pGicCpu->bBinaryPointGrp0 = 3; 3945 pGicCpu->bBinaryPointGrp1 = 3; 3946 } 3947 3948 3949 /** 3950 * Initializes per-VM GIC to the state following a power-up or hardware 3951 * reset. 3952 * 3953 * @param pVM The cross context VM structure. 3954 */ 3955 DECLHIDDEN(void) gicReset(PPDMDEVINS pDevIns) 3956 { 3957 LogFlowFunc(("\n")); 3958 gicInit(pDevIns); 1349 3959 } 1350 3960 … … 1356 3966 * @param pVCpu The cross context virtual CPU structure. 1357 3967 */ 1358 DECLHIDDEN(void) gicResetCpu(P VMCPUCC pVCpu)1359 { 1360 LogFlowFunc((" GIC%u\n", pVCpu->idCpu));3968 DECLHIDDEN(void) gicResetCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu) 3969 { 3970 LogFlowFunc(("[%u]\n", pVCpu->idCpu)); 1361 3971 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu); 1362 1363 memset((void *)&pVCpu->gic.s.abRunningPriorities[0], 0xff, sizeof(pVCpu->gic.s.abRunningPriorities)); 1364 pVCpu->gic.s.idxRunningPriority = 0; 1365 pVCpu->gic.s.bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */ 3972 gicInitCpu(pDevIns, pVCpu); 1366 3973 } 1367 3974 … … 1376 3983 Assert(cb == 4); RT_NOREF_PV(cb); 1377 3984 1378 PVMCPUCC pVCpu 1379 uint16_t offReg 1380 uint32_t uValue 3985 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns); 3986 uint16_t offReg = off & 0xfffc; 3987 uint32_t uValue = 0; 1381 3988 1382 3989 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead)); 1383 3990 1384 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRe gisterRead(pDevIns, pVCpu, offReg, &uValue));3991 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistReadRegister(pDevIns, pVCpu, offReg, &uValue)); 1385 3992 *(uint32_t *)pv = uValue; 1386 3993 1387 Log 2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));3994 LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue)); 1388 3995 return rc; 1389 3996 } … … 1399 4006 Assert(cb == 4); RT_NOREF_PV(cb); 1400 4007 1401 PVMCPUCC pVCpu 1402 uint16_t offReg 1403 uint32_t uValue 4008 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns); 4009 uint16_t offReg = off & 0xfffc; 4010 uint32_t uValue = *(uint32_t *)pv; 1404 4011 1405 4012 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite)); 1406 1407 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue)); 1408 return gicDist RegisterWrite(pDevIns, pVCpu, offReg, uValue);4013 LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue)); 4014 4015 return gicDistWriteRegister(pDevIns, pVCpu, offReg, uValue); 1409 4016 } 1410 4017 … … 1424 4031 * and the redistributors are adjacent. 1425 4032 */ 1426 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);4033 uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); 1427 4034 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); 1428 4035 1429 4036 PVMCC pVM = PDMDevHlpGetVM(pDevIns); 1430 4037 Assert(idReDist < pVM->cCpus); 1431 PVMCPUCC pVCpu = pVM-> apCpusR3[idReDist];4038 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist]; 1432 4039 1433 4040 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead)); 1434 4041 1435 4042 /* Redistributor or SGI/PPI frame? */ 1436 uint16_t offReg = off & 0xfffc;1437 uint32_t uValue = 0;4043 uint16_t const offReg = off & 0xfffc; 4044 uint32_t uValue = 0; 1438 4045 VBOXSTRICTRC rcStrict; 1439 4046 if (off < GIC_REDIST_REG_FRAME_SIZE) 1440 rcStrict = gicReDistRe gisterRead(pDevIns, pVCpu, idReDist, offReg, &uValue);4047 rcStrict = gicReDistReadRegister(pDevIns, pVCpu, idReDist, offReg, &uValue); 1441 4048 else 1442 rcStrict = gicReDist SgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);4049 rcStrict = gicReDistReadSgiPpiRegister(pDevIns, pVCpu, offReg, &uValue); 1443 4050 1444 4051 *(uint32_t *)pv = uValue; 1445 Log 2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",1446 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));4052 LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg, 4053 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict))); 1447 4054 return rcStrict; 1448 4055 } … … 1465 4072 * and the redistributors are adjacent. 1466 4073 */ 1467 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);4074 uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); 1468 4075 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); 1469 4076 1470 P VMCC pVM = PDMDevHlpGetVM(pDevIns);4077 PCVMCC pVM = PDMDevHlpGetVM(pDevIns); 1471 4078 Assert(idReDist < pVM->cCpus); 1472 PVMCPUCC pVCpu = pVM-> apCpusR3[idReDist];4079 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist]; 1473 4080 1474 4081 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite)); 1475 4082 1476 4083 /* Redistributor or SGI/PPI frame? */ 1477 uint16_t offReg = off & 0xfffc;4084 uint16_t const offReg = off & 0xfffc; 1478 4085 VBOXSTRICTRC rcStrict; 1479 4086 if (off < GIC_REDIST_REG_FRAME_SIZE) 1480 rcStrict = gicReDist RegisterWrite(pDevIns, pVCpu, offReg, uValue);4087 rcStrict = gicReDistWriteRegister(pDevIns, pVCpu, offReg, uValue); 1481 4088 else 1482 rcStrict = gicReDist SgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);1483 1484 Log 2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",1485 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));4089 rcStrict = gicReDistWriteSgiPpiRegister(pDevIns, pVCpu, offReg, uValue); 4090 4091 LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg, 4092 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict))); 1486 4093 return rcStrict; 1487 4094 } … … 1489 4096 1490 4097 #ifndef IN_RING3 1491 1492 4098 /** 1493 4099 * @callback_method_impl{PDMDEVREGR0,pfnConstruct} … … 1500 4106 } 1501 4107 #endif /* !IN_RING3 */ 4108 1502 4109 1503 4110 /** … … 1574 4181 }; 1575 4182 4183 1576 4184 /** 1577 4185 * The VirtualBox GIC backend.
Note:
See TracChangeset
for help on using the changeset viewer.