Changeset 39306 in vbox for trunk/src/VBox/Devices/PC
- Timestamp:
- Nov 15, 2011 1:14:13 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevAPIC.cpp
r39136 r39306 6 6 7 7 /* 8 * Copyright (C) 2006-201 0Oracle Corporation8 * Copyright (C) 2006-2011 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 48 48 #include <VBox/log.h> 49 49 #include <VBox/vmm/stam.h> 50 #include <VBox/vmm/vmcpuset.h> 51 #include <iprt/asm.h> 50 52 #include <iprt/assert.h> 51 #include <iprt/asm.h>52 53 53 54 #include <VBox/msi.h> … … 125 126 } while (0) 126 127 127 #define foreach_apic(pDev, mask, code) \ 128 do { \ 129 APICState *apic = (pDev)->CTX_SUFF(paLapics); \ 130 for (uint32_t i = 0; i < (pDev)->cCpus; i++) \ 131 { \ 132 if (mask & (1 << (apic->id))) \ 133 { \ 134 code; \ 135 } \ 136 apic++; \ 137 } \ 128 /** 129 * Begins an APIC enumeration block. 130 * 131 * Code placed between this and the APIC_FOREACH_END macro will be executed for 132 * each APIC instance present in the system. 133 * 134 * @param a_pDev The APIC device. 135 */ 136 #define APIC_FOREACH_BEGIN(a_pDev) \ 137 do { \ 138 VMCPUID const cApics = (a_pDev)->cCpus; \ 139 APICState *pCurApic = (a_pDev)->CTX_SUFF(paLapics); \ 140 for (VMCPUID iCurApic = 0; iCurApic < cApics; iCurApic++, pCurApic++) \ 141 { \ 142 do { } while (0) 143 144 /** 145 * Begins an APIC enumeration block, given a destination set. 146 * 147 * Code placed between this and the APIC_FOREACH_END macro will be executed for 148 * each APIC instance present in @a a_pDstSet. 149 * 150 * @param a_pDev The APIC device. 151 * @param a_pDstSet The destination set. 152 */ 153 #define APIC_FOREACH_IN_SET_BEGIN(a_pDev, a_pDstSet) \ 154 APIC_FOREACH_BEGIN(a_pDev); \ 155 if (!VMCPUSET_IS_PRESENT((a_pDstSet), iCurApic)) \ 156 continue; \ 157 do { } while (0) 158 159 160 /** Counterpart to APIC_FOREACH_IN_SET_BEGIN and APIC_FOREACH_BEGIN. */ 161 #define APIC_FOREACH_END() \ 162 } \ 138 163 } while (0) 139 140 # define set_bit(pvBitmap, iBit) ASMBitSet(pvBitmap, iBit)141 # define reset_bit(pvBitmap, iBit) ASMBitClear(pvBitmap, iBit)142 # define fls_bit(value) (ASMBitLastSetU32(value) - 1)143 # define ffs_bit(value) (ASMBitFirstSetU32(value) - 1)144 164 145 165 #define DEBUG_APIC … … 190 210 * Structures and Typedefs * 191 211 *******************************************************************************/ 192 typedef struct APICState { 212 typedef struct APIC256BITREG 213 { 214 /** The bitmap data. */ 215 uint32_t au32Bitmap[8 /*256/32*/]; 216 } APIC256BITREG; 217 typedef APIC256BITREG *PAPIC256BITREG; 218 typedef APIC256BITREG const *PCAPIC256BITREG; 219 220 /** 221 * Tests if a bit in the 256-bit APIC register is set. 222 * 223 * @returns true if set, false if clear. 224 * 225 * @param pReg The register. 226 * @param iBit The bit to test for. 227 */ 228 DECLINLINE(bool) Apic256BitReg_IsBitSet(PCAPIC256BITREG pReg, unsigned iBit) 229 { 230 Assert(iBit < 256); 231 return ASMBitTest(&pReg->au32Bitmap[0], iBit); 232 } 233 234 235 /** 236 * Sets a bit in the 256-bit APIC register is set. 237 * 238 * @param pReg The register. 239 * @param iBit The bit to set. 240 */ 241 DECLINLINE(void) Apic256BitReg_SetBit(PAPIC256BITREG pReg, unsigned iBit) 242 { 243 Assert(iBit < 256); 244 return ASMBitSet(&pReg->au32Bitmap[0], iBit); 245 } 246 247 248 /** 249 * Clears a bit in the 256-bit APIC register is set. 250 * 251 * @param pReg The register. 252 * @param iBit The bit to clear. 253 */ 254 DECLINLINE(void) Apic256BitReg_ClearBit(PAPIC256BITREG pReg, unsigned iBit) 255 { 256 Assert(iBit < 256); 257 return ASMBitClear(&pReg->au32Bitmap[0], iBit); 258 } 259 260 /** 261 * Clears all bits in the 256-bit APIC register set. 262 * 263 * @param pReg The register. 264 */ 265 DECLINLINE(void) Apic256BitReg_Empty(PAPIC256BITREG pReg) 266 { 267 memset(&pReg->au32Bitmap[0], 0, sizeof(pReg->au32Bitmap)); 268 } 269 270 /** 271 * Finds the last bit set in the register, i.e. the highest priority interrupt. 272 * 273 * @returns The index of the found bit, @a iRetAllClear if none was found. 274 * 275 * @param pReg The register. 276 * @param iRetAllClear What to return if all bits are clear. 277 */ 278 static int Apic256BitReg_FindLastSetBit(PCAPIC256BITREG pReg, int iRetAllClear) 279 { 280 uint32_t i = RT_ELEMENTS(pReg->au32Bitmap); 281 while (i-- > 0) 282 { 283 uint32_t u = pReg->au32Bitmap[i]; 284 if (u) 285 { 286 u = ASMBitLastSetU32(u); 287 u--; 288 u |= i << 5; 289 return (int)u; 290 } 291 } 292 return iRetAllClear; 293 } 294 295 296 typedef struct APICState 297 { 193 298 uint32_t apicbase; 194 299 /* Task priority register (interrupt level) */ … … 203 308 uint8_t log_dest; 204 309 uint8_t dest_mode; 205 uint32_t isr[8]; /*in service register */206 uint32_t tmr[8]; /*trigger mode register */207 uint32_t irr[8]; /*interrupt request register */310 APIC256BITREG isr; /**< in service register */ 311 APIC256BITREG tmr; /**< trigger mode register */ 312 APIC256BITREG irr; /**< interrupt request register */ 208 313 uint32_t lvt[APIC_LVT_NB]; 209 314 uint32_t esr; /* error register */ … … 319 424 320 425 static void apic_eoi(APICDeviceInfo *pDev, APICState* s); /* */ 321 static uint32_t apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode);426 static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo* pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet); 322 427 static int apic_deliver(APICDeviceInfo* pDev, APICState *s, 323 428 uint8_t dest, uint8_t dest_mode, … … 359 464 LogFlow(("apic: setting interrupt flag for cpu %d\n", getCpuFromLapic(pDev, s))); 360 465 pDev->CTX_SUFF(pApicHlp)->pfnSetInterruptFF(pDev->CTX_SUFF(pDevIns), enmType, 361 getCpuFromLapic(pDev, s));466 getCpuFromLapic(pDev, s)); 362 467 } 363 468 … … 366 471 LogFlow(("apic: clear interrupt flag\n")); 367 472 pDev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(pDev->CTX_SUFF(pDevIns), enmType, 368 getCpuFromLapic(pDev, s));473 getCpuFromLapic(pDev, s)); 369 474 } 370 475 … … 376 481 377 482 pDev->pApicHlpR3->pfnSendSipi(pDev->pDevInsR3, 378 getCpuFromLapic(pDev, s),379 vector);483 getCpuFromLapic(pDev, s), 484 vector); 380 485 } 381 486 … … 424 529 425 530 static int apic_bus_deliver(APICDeviceInfo* pDev, 426 uint32_t deliver_bitmask, uint8_t delivery_mode,531 PCVMCPUSET pDstSet, uint8_t delivery_mode, 427 532 uint8_t vector_num, uint8_t polarity, 428 533 uint8_t trigger_mode) 429 534 { 430 LogFlow(("apic_bus_deliver mask=%x mode=%x vector=%x polarity=%x trigger_mode=%x\n", deliver_bitmask, delivery_mode, vector_num, polarity, trigger_mode)); 431 switch (delivery_mode) { 535 LogFlow(("apic_bus_deliver mask=%R[vmcpuset] mode=%x vector=%x polarity=%x trigger_mode=%x\n", 536 pDstSet, delivery_mode, vector_num, polarity, trigger_mode)); 537 538 switch (delivery_mode) 539 { 432 540 case APIC_DM_LOWPRI: 433 541 { 434 int d = -1; 435 if (deliver_bitmask) 436 d = ffs_bit(deliver_bitmask); 437 if (d >= 0) 542 VMCPUID idDstCpu = VMCPUSET_FIND_FIRST_PRESENT(pDstSet); 543 if (idDstCpu != NIL_VMCPUID) 438 544 { 439 APICState * apic = getLapicById(pDev, d);440 apic_set_irq(pDev, apic, vector_num, trigger_mode);545 APICState *pApic = getLapicById(pDev, idDstCpu); 546 apic_set_irq(pDev, pApic, vector_num, trigger_mode); 441 547 } 442 548 return VINF_SUCCESS; 443 549 } 550 444 551 case APIC_DM_FIXED: 445 /* XXX: arbitration */552 /** @todo XXX: arbitration */ 446 553 break; 447 554 448 555 case APIC_DM_SMI: 449 foreach_apic(pDev, deliver_bitmask, 450 cpuSetInterrupt(pDev, apic, PDMAPICIRQ_SMI)); 556 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); 557 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_SMI); 558 APIC_FOREACH_END(); 451 559 return VINF_SUCCESS; 452 560 453 561 case APIC_DM_NMI: 454 foreach_apic(pDev, deliver_bitmask, 455 cpuSetInterrupt(pDev, apic, PDMAPICIRQ_NMI)); 562 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); 563 cpuSetInterrupt(pDev, pCurApic, PDMAPICIRQ_NMI); 564 APIC_FOREACH_END(); 456 565 return VINF_SUCCESS; 457 566 … … 459 568 /* normal INIT IPI sent to processors */ 460 569 #ifdef IN_RING3 461 foreach_apic(pDev, deliver_bitmask, 462 apicSendInitIpi(pDev, apic)); 570 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); 571 apicSendInitIpi(pDev, pCurApic); 572 APIC_FOREACH_END(); 463 573 return VINF_SUCCESS; 464 574 #else 465 /* We shall send init IPI only in R3, R0 calls should be 466 rescheduled to R3 */ 575 /* We shall send init IPI only in R3. */ 467 576 return VINF_IOM_HC_MMIO_READ_WRITE; 468 577 #endif /* IN_RING3 */ 578 469 579 case APIC_DM_EXTINT: 470 580 /* handled in I/O APIC code */ … … 475 585 } 476 586 477 foreach_apic(pDev, deliver_bitmask, 478 apic_set_irq (pDev, apic, vector_num, trigger_mode)); 587 APIC_FOREACH_IN_SET_BEGIN(pDev, pDstSet); 588 apic_set_irq(pDev, pCurApic, vector_num, trigger_mode); 589 APIC_FOREACH_END(); 479 590 return VINF_SUCCESS; 480 591 } … … 712 823 APIC_LOCK(pDev, rcBusy); 713 824 int vector = u64Value & 0xff; 825 VMCPUSET SelfSet; 826 VMCPUSET_EMPTY(&SelfSet); 827 VMCPUSET_ADD(&SelfSet, pApic->id); 714 828 rc = apic_bus_deliver(pDev, 715 1 << pApic->id /* Self */,829 &SelfSet, 716 830 0 /* Delivery mode - fixed */, 717 831 vector, … … 838 952 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: 839 953 APIC_LOCK(pDev, rcBusy); 840 *pu64Value = pApic->isr [iReg & 7];954 *pu64Value = pApic->isr.au32Bitmap[iReg & 7]; 841 955 APIC_UNLOCK(pDev); 842 956 break; … … 844 958 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: 845 959 APIC_LOCK(pDev, rcBusy); 846 *pu64Value = pApic->tmr [iReg & 7];960 *pu64Value = pApic->tmr.au32Bitmap[iReg & 7]; 847 961 APIC_UNLOCK(pDev); 848 962 break; … … 850 964 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: 851 965 APIC_LOCK(pDev, rcBusy); 852 *pu64Value = pApic->irr [iReg & 7];966 *pu64Value = pApic->irr.au32Bitmap[iReg & 7]; 853 967 APIC_UNLOCK(pDev); 854 968 break; … … 963 1077 */ 964 1078 PDMBOTHCBDECL(int) apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, 965 966 1079 uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity, 1080 uint8_t u8TriggerMode) 967 1081 { 968 1082 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); … … 970 1084 LogFlow(("apicBusDeliverCallback: pDevIns=%p u8Dest=%#x u8DestMode=%#x u8DeliveryMode=%#x iVector=%#x u8Polarity=%#x u8TriggerMode=%#x\n", 971 1085 pDevIns, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode)); 972 return apic_bus_deliver(pDev, apic_get_delivery_bitmask(pDev, u8Dest, u8DestMode), 1086 VMCPUSET DstSet; 1087 return apic_bus_deliver(pDev, apic_get_delivery_bitmask(pDev, u8Dest, u8DestMode, &DstSet), 973 1088 u8DeliveryMode, iVector, u8Polarity, u8TriggerMode); 974 1089 } … … 1064 1179 } 1065 1180 1066 /* return -1 if no bit is set */1067 static int get_highest_priority_int(uint32_t const *tab)1068 {1069 int i;1070 for(i = 7; i >= 0; i--) {1071 if (tab[i] != 0) {1072 return i * 32 + fls_bit(tab[i]);1073 }1074 }1075 return -1;1076 }1077 1078 1181 static int apic_get_ppr(APICState const *s) 1079 1182 { 1080 int tpr, isrv, ppr; 1081 1082 tpr = (s->tpr >> 4); 1083 isrv = get_highest_priority_int(s->isr); 1084 if (isrv < 0) 1085 isrv = 0; 1183 int ppr; 1184 1185 int tpr = (s->tpr >> 4); 1186 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, 0); 1086 1187 isrv >>= 4; 1087 1188 if (tpr >= isrv) … … 1094 1195 static int apic_get_ppr_zero_tpr(APICState *s) 1095 1196 { 1096 int isrv; 1097 1098 isrv = get_highest_priority_int(s->isr); 1099 if (isrv < 0) 1100 isrv = 0; 1101 return isrv; 1197 return Apic256BitReg_FindLastSetBit(&s->isr, 0); 1102 1198 } 1103 1199 1104 1200 static int apic_get_arb_pri(APICState const *s) 1105 1201 { 1106 /* XXX: arbitration */1202 /** @todo XXX: arbitration */ 1107 1203 return 0; 1108 1204 } … … 1111 1207 static bool apic_update_irq(APICDeviceInfo *pDev, APICState* s) 1112 1208 { 1113 int irrv, ppr;1114 1209 if (!(s->spurious_vec & APIC_SV_ENABLE)) 1115 1210 { … … 1119 1214 } 1120 1215 1121 i rrv = get_highest_priority_int(s->irr);1216 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1); 1122 1217 if (irrv < 0) 1123 1218 return false; 1124 ppr = apic_get_ppr(s);1219 int ppr = apic_get_ppr(s); 1125 1220 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) 1126 1221 return false; … … 1132 1227 PDMBOTHCBDECL(bool) apicHasPendingIrq(PPDMDEVINS pDevIns) 1133 1228 { 1134 int irrv, ppr;1135 1229 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); 1136 1230 if (!pDev) … … 1143 1237 /* 1144 1238 * All our callbacks now come from single IOAPIC, thus locking 1145 * seems to be excessive now (@todo: check)1239 * seems to be excessive now 1146 1240 */ 1147 irrv = get_highest_priority_int(s->irr); 1241 /** @todo check excessive locking whatever... */ 1242 int irrv = Apic256BitReg_FindLastSetBit(&s->irr, -1); 1148 1243 if (irrv < 0) 1149 1244 return false; 1150 1245 1151 ppr = apic_get_ppr_zero_tpr(s);1246 int ppr = apic_get_ppr_zero_tpr(s); 1152 1247 1153 1248 if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) … … 1178 1273 { 1179 1274 LogFlow(("CPU%d: apic_set_irq vector=%x, trigger_mode=%x\n", s->phys_id, vector_num, trigger_mode)); 1180 set_bit(s->irr, vector_num);1275 Apic256BitReg_SetBit(&s->irr, vector_num); 1181 1276 if (trigger_mode) 1182 set_bit(s->tmr, vector_num);1277 Apic256BitReg_SetBit(&s->tmr, vector_num); 1183 1278 else 1184 reset_bit(s->tmr, vector_num);1279 Apic256BitReg_ClearBit(&s->tmr, vector_num); 1185 1280 apic_update_irq(pDev, s); 1186 1281 } … … 1188 1283 static void apic_eoi(APICDeviceInfo *pDev, APICState* s) 1189 1284 { 1190 int isrv; 1191 isrv = get_highest_priority_int(s->isr); 1285 int isrv = Apic256BitReg_FindLastSetBit(&s->isr, -1); 1192 1286 if (isrv < 0) 1193 1287 return; 1194 reset_bit(s->isr, isrv);1288 Apic256BitReg_ClearBit(&s->isr, isrv); 1195 1289 LogFlow(("CPU%d: apic_eoi isrv=%x\n", s->phys_id, isrv)); 1196 /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to1197 set the remote IRR bit for level triggered interrupts. */1290 /** @todo XXX: send the EOI packet to the APIC bus to allow the I/O APIC to 1291 * set the remote IRR bit for level triggered interrupts. */ 1198 1292 apic_update_irq(pDev, s); 1199 1293 } 1200 1294 1201 static uint32_t apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode)1202 { 1203 uint32_t mask = 0;1295 static PVMCPUSET apic_get_delivery_bitmask(APICDeviceInfo *pDev, uint8_t dest, uint8_t dest_mode, PVMCPUSET pDstSet) 1296 { 1297 VMCPUSET_EMPTY(pDstSet); 1204 1298 1205 1299 if (dest_mode == 0) 1206 1300 { 1207 1301 if (dest == 0xff) 1208 mask = 0xff; 1302 { 1303 /* was: mask = 0xff; - weird */ /** @todo check this; could this (1) differ on X2APIC and (2) actully mean a broadcast? */ 1304 for (VMCPUID iCpu = 0; iCpu < 8; iCpu++) 1305 VMCPUSET_ADD(pDstSet, iCpu); 1306 } 1209 1307 else 1210 mask = 1 << dest;1308 VMCPUSET_ADD(pDstSet, dest); 1211 1309 } 1212 1310 else 1213 1311 { 1214 APICState *apic = pDev->CTX_SUFF(paLapics); 1215 uint32_t i; 1216 1217 /* XXX: cluster mode */ 1218 for(i = 0; i < pDev->cCpus; i++) 1219 { 1220 if (apic->dest_mode == APIC_DESTMODE_FLAT) 1312 /** @todo XXX: cluster mode */ 1313 APIC_FOREACH_BEGIN(pDev); 1314 if (pCurApic->dest_mode == APIC_DESTMODE_FLAT) 1221 1315 { 1222 if (dest & apic->log_dest)1223 mask |= (1 << i);1316 if (dest & pCurApic->log_dest) 1317 VMCPUSET_ADD(pDstSet, iCurApic); 1224 1318 } 1225 else if ( apic->dest_mode == APIC_DESTMODE_CLUSTER)1319 else if (pCurApic->dest_mode == APIC_DESTMODE_CLUSTER) 1226 1320 { 1227 if ((dest & 0xf0) == (apic->log_dest & 0xf0) 1228 && 1229 (dest & apic->log_dest & 0x0f)) 1230 { 1231 mask |= (1 << i); 1232 } 1321 if ( (dest & 0xf0) == (pCurApic->log_dest & 0xf0) 1322 && (dest & pCurApic->log_dest & 0x0f)) 1323 VMCPUSET_ADD(pDstSet, iCurApic); 1233 1324 } 1234 apic++; 1235 } 1236 } 1237 1238 return mask; 1325 APIC_FOREACH_END(); 1326 } 1327 1328 return pDstSet; 1239 1329 } 1240 1330 … … 1250 1340 s->log_dest = 0; 1251 1341 s->dest_mode = 0xff; /** @todo 0xff???? */ 1252 memset(s->isr, 0, sizeof(s->isr));1253 memset(s->tmr, 0, sizeof(s->tmr));1254 memset(s->irr, 0, sizeof(s->irr));1342 Apic256BitReg_Empty(&s->isr); 1343 Apic256BitReg_Empty(&s->tmr); 1344 Apic256BitReg_Empty(&s->irr); 1255 1345 s->esr = 0; 1256 1346 memset(s->icr, 0, sizeof(s->icr)); … … 1277 1367 #endif /* IN_RING3 */ 1278 1368 1279 static int apic_deliver(APICDeviceInfo *pDev, APICState *s,1369 static int apic_deliver(APICDeviceInfo *pDev, APICState *s, 1280 1370 uint8_t dest, uint8_t dest_mode, 1281 1371 uint8_t delivery_mode, uint8_t vector_num, 1282 1372 uint8_t polarity, uint8_t trigger_mode) 1283 1373 { 1284 uint32_t deliver_bitmask = 0;1285 1374 int dest_shorthand = (s->icr[0] >> 18) & 3; 1286 1287 1375 LogFlow(("apic_deliver dest=%x dest_mode=%x dest_shorthand=%x delivery_mode=%x vector_num=%x polarity=%x trigger_mode=%x\n", dest, dest_mode, dest_shorthand, delivery_mode, vector_num, polarity, trigger_mode)); 1288 1376 1289 switch (dest_shorthand) { 1377 VMCPUSET DstSet; 1378 switch (dest_shorthand) 1379 { 1290 1380 case 0: 1291 deliver_bitmask = apic_get_delivery_bitmask(pDev, dest, dest_mode);1381 apic_get_delivery_bitmask(pDev, dest, dest_mode, &DstSet); 1292 1382 break; 1293 1383 case 1: 1294 deliver_bitmask = (1 << s->id); 1384 VMCPUSET_EMPTY(&DstSet); 1385 VMCPUSET_ADD(&DstSet, s->id); 1295 1386 break; 1296 1387 case 2: 1297 deliver_bitmask = 0xffffffff;1388 VMCPUSET_FILL(&DstSet); 1298 1389 break; 1299 1390 case 3: 1300 deliver_bitmask = 0xffffffff & ~(1 << s->id); 1301 break; 1302 } 1303 1304 switch (delivery_mode) { 1391 VMCPUSET_FILL(&DstSet); 1392 VMCPUSET_DEL(&DstSet, s->id); 1393 break; 1394 } 1395 1396 switch (delivery_mode) 1397 { 1305 1398 case APIC_DM_INIT: 1399 { 1400 uint32_t const trig_mode = (s->icr[0] >> 15) & 1; 1401 uint32_t const level = (s->icr[0] >> 14) & 1; 1402 if (level == 0 && trig_mode == 1) 1306 1403 { 1307 int trig_mode = (s->icr[0] >> 15) & 1; 1308 int level = (s->icr[0] >> 14) & 1; 1309 if (level == 0 && trig_mode == 1) { 1310 foreach_apic(pDev, deliver_bitmask, 1311 apic->arb_id = apic->id); 1312 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id)); 1313 return VINF_SUCCESS; 1314 } 1404 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet); 1405 pCurApic->arb_id = pCurApic->id; 1406 APIC_FOREACH_END(); 1407 Log(("CPU%d: APIC_DM_INIT arbitration id(s) set\n", s->phys_id)); 1408 return VINF_SUCCESS; 1315 1409 } 1316 1410 break; 1411 } 1317 1412 1318 1413 case APIC_DM_SIPI: 1319 1414 # ifdef IN_RING3 1320 foreach_apic(pDev, deliver_bitmask, 1321 apic_startup(pDev, apic, vector_num)); 1415 APIC_FOREACH_IN_SET_BEGIN(pDev, &DstSet); 1416 apic_startup(pDev, pCurApic, vector_num); 1417 APIC_FOREACH_END(); 1322 1418 return VINF_SUCCESS; 1323 1419 # else 1324 1420 /* We shall send SIPI only in R3, R0 calls should be 1325 1421 rescheduled to R3 */ 1326 return 1422 return VINF_IOM_HC_MMIO_WRITE; 1327 1423 # endif 1328 1424 } 1329 1425 1330 return apic_bus_deliver(pDev, deliver_bitmask, delivery_mode, vector_num,1426 return apic_bus_deliver(pDev, &DstSet, delivery_mode, vector_num, 1331 1427 polarity, trigger_mode); 1332 1428 } … … 1347 1443 1348 1444 APICState *s = getLapic(pDev); /** @todo fix interface */ 1349 int intno; 1350 1351 if (!(s->spurious_vec & APIC_SV_ENABLE)){1445 1446 if (!(s->spurious_vec & APIC_SV_ENABLE)) 1447 { 1352 1448 Log(("CPU%d: apic_get_interrupt: returns -1 (APIC_SV_ENABLE)\n", s->phys_id)); 1353 1449 return -1; 1354 1450 } 1355 1451 1356 /* XXX: spurious IRQ handling */ 1357 intno = get_highest_priority_int(s->irr); 1358 if (intno < 0) { 1452 /** @todo XXX: spurious IRQ handling */ 1453 int intno = Apic256BitReg_FindLastSetBit(&s->irr, -1); 1454 if (intno < 0) 1455 { 1359 1456 Log(("CPU%d: apic_get_interrupt: returns -1 (irr)\n", s->phys_id)); 1360 1457 return -1; 1361 1458 } 1362 if (s->tpr && (uint32_t)intno <= s->tpr) { 1459 1460 if (s->tpr && (uint32_t)intno <= s->tpr) 1461 { 1363 1462 Log(("apic_get_interrupt: returns %d (sp)\n", s->spurious_vec & 0xff)); 1364 1463 return s->spurious_vec & 0xff; 1365 1464 } 1366 reset_bit(s->irr, intno);1367 set_bit(s->isr, intno);1465 Apic256BitReg_ClearBit(&s->irr, intno); 1466 Apic256BitReg_SetBit(&s->isr, intno); 1368 1467 apic_update_irq(pDev, s); 1369 1468 LogFlow(("CPU%d: apic_get_interrupt: returns %d\n", s->phys_id, intno)); … … 1621 1720 SSMR3PutU8(f, s->dest_mode); 1622 1721 for (i = 0; i < 8; i++) { 1623 SSMR3PutU32(f, s->isr [i]);1624 SSMR3PutU32(f, s->tmr [i]);1625 SSMR3PutU32(f, s->irr [i]);1722 SSMR3PutU32(f, s->isr.au32Bitmap[i]); 1723 SSMR3PutU32(f, s->tmr.au32Bitmap[i]); 1724 SSMR3PutU32(f, s->irr.au32Bitmap[i]); 1626 1725 } 1627 1726 for (i = 0; i < APIC_LVT_NB; i++) { … … 1645 1744 int i; 1646 1745 1647 /*XXX: what if the base changes? (registered memory regions) */1746 /** @todo XXX: what if the base changes? (registered memory regions) */ 1648 1747 SSMR3GetU32(f, &s->apicbase); 1649 1748 … … 1675 1774 SSMR3GetU8(f, &s->dest_mode); 1676 1775 for (i = 0; i < 8; i++) { 1677 SSMR3GetU32(f, &s->isr [i]);1678 SSMR3GetU32(f, &s->tmr [i]);1679 SSMR3GetU32(f, &s->irr [i]);1776 SSMR3GetU32(f, &s->isr.au32Bitmap[i]); 1777 SSMR3GetU32(f, &s->tmr.au32Bitmap[i]); 1778 SSMR3GetU32(f, &s->irr.au32Bitmap[i]); 1680 1779 } 1681 1780 for (i = 0; i < APIC_LVT_NB; i++) { … … 1822 1921 static void apicR3DumpVec(APICDeviceInfo *pDev, APICState *pApic, PCDBGFINFOHLP pHlp, uint32_t iStartReg) 1823 1922 { 1824 for (uint32_t i = 0; i < 8; ++i)1923 for (uint32_t i = 0; i < 8; i++) 1825 1924 pHlp->pfnPrintf(pHlp, "%08x", apicR3InfoReadReg(pDev, pApic, iStartReg + i)); 1826 1925 pHlp->pfnPrintf(pHlp, "\n"); … … 1863 1962 pHlp->pfnPrintf(pHlp, " ISR : "); 1864 1963 apicR3DumpVec(pDev, pApic, pHlp, 0x10); 1865 int iMax = get_highest_priority_int(pApic->isr);1964 int iMax = Apic256BitReg_FindLastSetBit(&pApic->isr, -1); 1866 1965 pHlp->pfnPrintf(pHlp, " highest = %02x\n", iMax == -1 ? 0 : iMax); 1867 1966 pHlp->pfnPrintf(pHlp, " IRR : "); 1868 1967 apicR3DumpVec(pDev, pApic, pHlp, 0x20); 1869 iMax = get_highest_priority_int(pApic->irr);1968 iMax = Apic256BitReg_FindLastSetBit(&pApic->irr, -1); 1870 1969 pHlp->pfnPrintf(pHlp, " highest = %02X\n", iMax == -1 ? 0 : iMax); 1871 1970 } … … 1979 2078 apicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL); 1980 2079 1981 /* save all APICs data, @todo: is it correct? */ 1982 foreach_apic(pDev, 0xffffffff, apic_save(pSSM, apic)); 2080 /* save all APICs data */ /** @todo: is it correct? */ 2081 APIC_FOREACH_BEGIN(pDev); 2082 apic_save(pSSM, pCurApic); 2083 APIC_FOREACH_END(); 1983 2084 1984 2085 return VINF_SUCCESS; … … 1998 2099 1999 2100 /* config */ 2000 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30) { 2101 if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30) 2102 { 2001 2103 uint32_t cCpus; 2002 2104 int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc); 2003 2105 if (cCpus != pDev->cCpus) 2004 2106 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pDev->cCpus); 2107 2005 2108 bool fIoApic; 2006 2109 rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc); 2007 2110 if (fIoApic != pDev->fIoApic) 2008 2111 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pDev->fIoApic); 2112 2009 2113 uint32_t uApicVersion; 2010 2114 rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc); … … 2018 2122 /* load all APICs data */ /** @todo: is it correct? */ 2019 2123 APIC_LOCK(pDev, VERR_INTERNAL_ERROR_3); 2020 foreach_apic(pDev, 0xffffffff, 2021 if (apic_load(pSSM, apic, uVersion)) { 2022 AssertFailed(); 2023 APIC_UNLOCK(pDev); 2024 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 2025 } 2026 ); 2124 2125 int rc = VINF_SUCCESS; 2126 APIC_FOREACH_BEGIN(pDev); 2127 rc = apic_load(pSSM, pCurApic, uVersion); 2128 if (RT_FAILURE(rc)) 2129 break; 2130 APIC_FOREACH_END(); 2131 2027 2132 APIC_UNLOCK(pDev); 2028 return VINF_SUCCESS;2133 return rc; 2029 2134 } 2030 2135 … … 2039 2144 2040 2145 /* Reset all APICs. */ 2041 for (VMCPUID i = 0; i < pDev->cCpus; i++) { 2146 for (VMCPUID i = 0; i < pDev->cCpus; i++) 2147 { 2042 2148 APICState *pApic = &pDev->CTX_SUFF(paLapics)[i]; 2043 2149 TMTimerStop(pApic->CTX_SUFF(pTimer)); … … 2045 2151 /* Clear LAPIC state as if an INIT IPI was sent. */ 2046 2152 apic_init_ipi(pDev, pApic); 2153 2047 2154 /* The IDs are not touched by apic_init_ipi() and must be reset now. */ 2048 2155 pApic->arb_id = pApic->id = i; 2049 2156 Assert(pApic->id == pApic->phys_id); /* The two should match again. */ 2157 2050 2158 /* Reset should re-enable the APIC, see comment in msi.h */ 2051 2159 pApic->apicbase = VBOX_MSI_ADDR_BASE | MSR_IA32_APICBASE_ENABLE; … … 2109 2217 static DECLCALLBACK(int) apicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 2110 2218 { 2111 PDMAPICREG ApicReg; 2112 int rc; 2219 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *); 2113 2220 uint32_t i; 2114 bool fIoApic;2115 bool fGCEnabled;2116 bool fR0Enabled;2117 APICDeviceInfo *pDev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);2118 uint32_t cCpus;2119 2221 2120 2222 /* … … 2126 2228 * Validate configuration. 2127 2229 */ 2128 if (!CFGMR3AreValuesValid(pCfg, 2129 "IOAPIC\0" 2130 "GCEnabled\0" 2131 "R0Enabled\0" 2132 "NumCPUs\0")) 2133 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES; 2134 2135 rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true); 2230 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|RZEnabled|NumCPUs", ""); 2231 2232 bool fIoApic; 2233 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fIoApic, true); 2136 2234 if (RT_FAILURE(rc)) 2137 2235 return PDMDEV_SET_ERROR(pDevIns, rc, 2138 2236 N_("Configuration error: Failed to read \"IOAPIC\"")); 2139 2237 2140 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true); 2238 bool fRZEnabled; 2239 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &fRZEnabled, true); 2141 2240 if (RT_FAILURE(rc)) 2142 2241 return PDMDEV_SET_ERROR(pDevIns, rc, 2143 N_("Configuration error: Failed to query boolean value \"GCEnabled\"")); 2144 2145 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true); 2146 if (RT_FAILURE(rc)) 2147 return PDMDEV_SET_ERROR(pDevIns, rc, 2148 N_("Configuration error: Failed to query boolean value \"R0Enabled\"")); 2149 2242 N_("Configuration error: Failed to query boolean value \"RZEnabled\"")); 2243 2244 uint32_t cCpus; 2150 2245 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1); 2151 2246 if (RT_FAILURE(rc)) … … 2153 2248 N_("Configuration error: Failed to query integer value \"NumCPUs\"")); 2154 2249 2155 Log(("APIC: cCpus=%d fR0Enabled=%RTbool fGCEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fR0Enabled, fGCEnabled, fIoApic)); 2156 2157 /** @todo Current implementation is limited to 32 CPUs due to the use of 32 2158 * bits bitmasks. */ 2159 if (cCpus > 32) 2250 Log(("APIC: cCpus=%d fRZEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fRZEnabled, fIoApic)); 2251 if (cCpus > 255) 2160 2252 return PDMDEV_SET_ERROR(pDevIns, rc, 2161 2253 N_("Configuration error: Invalid value for \"NumCPUs\"")); … … 2193 2285 * Register the APIC. 2194 2286 */ 2287 PDMAPICREG ApicReg; 2195 2288 ApicReg.u32Version = PDM_APICREG_VERSION; 2196 2289 ApicReg.pfnGetInterruptR3 = apicGetInterrupt; … … 2204 2297 ApicReg.pfnBusDeliverR3 = apicBusDeliverCallback; 2205 2298 ApicReg.pfnLocalInterruptR3 = apicLocalInterrupt; 2206 if (fGCEnabled) { 2299 if (fRZEnabled) 2300 { 2207 2301 ApicReg.pszGetInterruptRC = "apicGetInterrupt"; 2208 2302 ApicReg.pszHasPendingIrqRC = "apicHasPendingIrq"; … … 2215 2309 ApicReg.pszBusDeliverRC = "apicBusDeliverCallback"; 2216 2310 ApicReg.pszLocalInterruptRC = "apicLocalInterrupt"; 2217 } else { 2311 2312 ApicReg.pszGetInterruptR0 = "apicGetInterrupt"; 2313 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq"; 2314 ApicReg.pszSetBaseR0 = "apicSetBase"; 2315 ApicReg.pszGetBaseR0 = "apicGetBase"; 2316 ApicReg.pszSetTPRR0 = "apicSetTPR"; 2317 ApicReg.pszGetTPRR0 = "apicGetTPR"; 2318 ApicReg.pszWriteMSRR0 = "apicWriteMSR"; 2319 ApicReg.pszReadMSRR0 = "apicReadMSR"; 2320 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback"; 2321 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt"; 2322 } 2323 else 2324 { 2218 2325 ApicReg.pszGetInterruptRC = NULL; 2219 2326 ApicReg.pszHasPendingIrqRC = NULL; … … 2226 2333 ApicReg.pszBusDeliverRC = NULL; 2227 2334 ApicReg.pszLocalInterruptRC = NULL; 2228 } 2229 if (fR0Enabled) { 2230 ApicReg.pszGetInterruptR0 = "apicGetInterrupt"; 2231 ApicReg.pszHasPendingIrqR0 = "apicHasPendingIrq"; 2232 ApicReg.pszSetBaseR0 = "apicSetBase"; 2233 ApicReg.pszGetBaseR0 = "apicGetBase"; 2234 ApicReg.pszSetTPRR0 = "apicSetTPR"; 2235 ApicReg.pszGetTPRR0 = "apicGetTPR"; 2236 ApicReg.pszWriteMSRR0 = "apicWriteMSR"; 2237 ApicReg.pszReadMSRR0 = "apicReadMSR"; 2238 ApicReg.pszBusDeliverR0 = "apicBusDeliverCallback"; 2239 ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt"; 2240 } else { 2335 2241 2336 ApicReg.pszGetInterruptR0 = NULL; 2242 2337 ApicReg.pszHasPendingIrqR0 = NULL; … … 2261 2356 uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx; 2262 2357 PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx); 2263 if (u32Eax >= 1) { 2358 if (u32Eax >= 1) 2359 { 2264 2360 if ( fIoApic /* If IOAPIC is enabled, enable Local APIC in any case */ 2265 2361 || ( u32Ebx == X86_CPUID_VENDOR_INTEL_EBX … … 2268 2364 || ( u32Ebx == X86_CPUID_VENDOR_AMD_EBX 2269 2365 && u32Ecx == X86_CPUID_VENDOR_AMD_ECX 2270 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */)) { 2366 && u32Edx == X86_CPUID_VENDOR_AMD_EDX /* AuthenticAMD */)) 2367 { 2271 2368 LogRel(("Activating Local APIC\n")); 2272 2369 pDev->pApicHlpR3->pfnChangeFeature(pDevIns, pDev->enmVersion); … … 2276 2373 /* 2277 2374 * Register the MMIO range. 2278 * @todo: shall reregister, if base changes.2279 2375 */ 2376 /** @todo: shall reregister, if base changes. */ 2280 2377 uint32_t ApicBase = pDev->paLapicsR3[0].apicbase & ~0xfff; 2281 2378 rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pDev, … … 2285 2382 return rc; 2286 2383 2287 if (fGCEnabled) { 2384 if (fRZEnabled) 2385 { 2288 2386 pDev->pApicHlpRC = pDev->pApicHlpR3->pfnGetRCHelpers(pDevIns); 2289 2387 pDev->pCritSectRC = pDev->pApicHlpR3->pfnGetRCCritSect(pDevIns); 2290 2291 2388 rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, NIL_RTRCPTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead"); 2292 2389 if (RT_FAILURE(rc)) 2293 2390 return rc; 2294 } 2295 2296 if (fR0Enabled) { 2391 2297 2392 pDev->pApicHlpR0 = pDev->pApicHlpR3->pfnGetR0Helpers(pDevIns); 2298 2393 pDev->pCritSectR0 = pDev->pApicHlpR3->pfnGetR0CritSect(pDevIns); 2299 2300 2394 rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, NIL_RTR0PTR /*pvUser*/, "apicMMIOWrite", "apicMMIORead"); 2301 2395 if (RT_FAILURE(rc)) … … 2306 2400 * Create the APIC timers. 2307 2401 */ 2308 for (i = 0; i < cCpus; i++) { 2402 for (i = 0; i < cCpus; i++) 2403 { 2309 2404 APICState *pApic = &pDev->paLapicsR3[i]; 2310 2405 pApic->pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_USER, "APIC Timer #%u", i); … … 2341 2436 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatMMIOWriteHC, STAMTYPE_COUNTER, "/Devices/APIC/MMIOWriteHC", STAMUNIT_OCCURENCES, "Number of APIC MMIO writes in HC."); 2342 2437 PDMDevHlpSTAMRegister(pDevIns, &pDev->StatClearedActiveIrq,STAMTYPE_COUNTER, "/Devices/APIC/MaskedActiveIRQ", STAMUNIT_OCCURENCES, "Number of cleared irqs."); 2343 for (i = 0; i < cCpus; i++) { 2438 for (i = 0; i < cCpus; i++) 2439 { 2344 2440 APICState *pApic = &pDev->paLapicsR3[i]; 2345 2441 PDMDevHlpSTAMRegisterF(pDevIns, &pApic->StatTimerSetInitialCount, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Calls to apicTimerSetInitialCount.", "/Devices/APIC/%u/TimerSetInitialCount", i);
Note:
See TracChangeset
for help on using the changeset viewer.