Changeset 44681 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Feb 14, 2013 8:56:49 AM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 83776
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevIoApic.cpp
r44679 r44681 276 276 } 277 277 278 static void ioapic_mem_writel(PIOAPIC pThis, RTGCPHYS addr, uint32_t val) 279 { 280 int index; 281 282 addr &= 0xff; 283 if (addr == 0x00) 284 { 285 pThis->ioregsel = val; 286 return; 287 } 288 289 if (addr == 0x10) 290 { 291 #ifdef DEBUG_IOAPIC 292 Log(("I/O APIC write: %08x = %08x\n", pThis->ioregsel, val)); 293 #endif 294 switch (pThis->ioregsel) 278 /** Handles a write to the IOREGSEL register. */ 279 static int ioapic_IoRegSel_w(PIOAPIC pThis, uint32_t u32Value) 280 { 281 Log2(("ioapic: IOREGSEL %#04x -> %#04x\n", pThis->ioregsel, u32Value & 0xff)); 282 pThis->ioregsel = u32Value & 0xff; /* This is what the AMD box does here */ 283 return VINF_SUCCESS; 284 } 285 286 /** 287 * Handles a write to the IOWIN register. 288 */ 289 static int ioapic_IoWin_w(PIOAPIC pThis, uint32_t u32Value) 290 { 291 uint32_t const uIoRegSel = pThis->ioregsel; 292 Log2(("ioapic: IOWIN[%#04x] = %#x\n", uIoRegSel, u32Value)); 293 294 /* 295 * IOREGSEL. 296 */ 297 if (uIoRegSel == 0) 298 { 299 /* Note! Compared to the 82093AA spec, we've extended the IOAPIC 300 identification from bits 27:24 to bits 31:24. */ 301 Log(("ioapic: IOAPICID %#x -> %#x\n", pThis->id, u32Value >> 24)); 302 pThis->id = u32Value >> 24; 303 } 304 /* 305 * IOREDTBL0..IOREDTBL23. 306 */ 307 else if (uIoRegSel - UINT32_C(0x10) < IOAPIC_NUM_PINS * 2) 308 { 309 uint32_t const idxIoRedTbl = (uIoRegSel - UINT32_C(0x10)) >> 1; 310 uint64_t u64NewValue; 311 if (!(uIoRegSel & 1)) 295 312 { 296 case 0x00: 297 pThis->id = (val >> 24) & 0xff; 298 return; 299 300 case 0x01: 301 case 0x02: 302 return; 303 304 default: 305 index = (pThis->ioregsel - 0x10) >> 1; 306 if (index >= 0 && index < IOAPIC_NUM_PINS) 307 { 308 if (pThis->ioregsel & 1) 309 { 310 pThis->ioredtbl[index] &= 0xffffffff; 311 pThis->ioredtbl[index] |= (uint64_t)val << 32; 312 } 313 else 314 { 315 /* According to IOAPIC spec, vectors should be from 0x10 to 0xfe */ 316 uint8_t vec = val & 0xff; 317 if ( (val & APIC_LVT_MASKED) 318 || (vec >= 0x10 && vec < 0xff) ) 319 { 320 pThis->ioredtbl[index] &= ~0xffffffffULL; 321 pThis->ioredtbl[index] |= val; 322 } 323 else 324 { 325 /* 326 * Linux 2.6 kernels has pretty strange function 327 * unlock_ExtINT_logic() which writes absolutely 328 * bogus (all 0) value into the vector with pretty 329 * vague explanation why. So we just ignore such 330 * writes. 331 */ 332 LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %d\n", val, pThis->ioregsel, index)); 333 } 334 } 335 ioapic_service(pThis); 336 } 313 /* 314 * Low DWORD. 315 * 316 * Have to do some sanity checks here because Linux 2.6 kernels 317 * writes seemingly bogus value (u32Value = 0) in their 318 * unlock_ExtINT_logic() function. Not sure what it's good for, but 319 * we ran into trouble with INTVEC = 0. Luckily the 82093AA specs 320 * limits the INTVEC range to 0x10 thru 0xfe, so we use this to 321 * ignore harmful values. 322 */ 323 /** @todo see what happens on real HW when doing that. It probably 324 * ignores/rejects other values as well. Could be it ignores invalid 325 * values on a per sub-register basis, someone need to check this! */ 326 if ( (u32Value & APIC_LVT_MASKED) 327 || ((u32Value & UINT32_C(0xff)) - UINT32_C(0x10)) <= UINT32_C(0xee) /* (0xfe - 0x10 = 0xee) */ ) 328 u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0xffffffff00000000)) | u32Value; 329 else 330 { 331 LogRel(("IOAPIC GUEST BUG: bad vector writing %x(sel=%x) to %u\n", u32Value, uIoRegSel, idxIoRedTbl)); 332 u64NewValue = pThis->ioredtbl[idxIoRedTbl]; 333 } 337 334 } 338 } 335 else 336 { 337 /* 338 * High DWORD. 339 */ 340 u64NewValue = (pThis->ioredtbl[idxIoRedTbl] & UINT64_C(0x00000000ffffffff)) | ((uint64_t)u32Value << 32); 341 } 342 343 Log(("ioapic: IOREDTBL%u %#018llx -> %#018llx\n", idxIoRedTbl, pThis->ioredtbl[idxIoRedTbl], u64NewValue)); 344 pThis->ioredtbl[idxIoRedTbl] = u64NewValue; 345 346 ioapic_service(pThis); 347 } 348 /* 349 * Read-only or unknown registers. Log it. 350 */ 351 else if (uIoRegSel == 1) 352 Log(("ioapic: Attempt to write (%#x) to IOAPICVER.\n", u32Value)); 353 else if (uIoRegSel == 2) 354 Log(("ioapic: Attempt to write (%#x) to IOAPICARB.\n", u32Value)); 355 else 356 Log(("ioapic: Attempt to write (%#x) to register %#x.\n", u32Value, uIoRegSel)); 357 358 return VINF_SUCCESS; 339 359 } 340 360 … … 376 396 STAM_COUNTER_INC(&CTXSUFF(pThis->StatMMIOWrite)); 377 397 IOAPIC_LOCK(pThis, VINF_IOM_R3_MMIO_WRITE); 378 switch (cb) 379 { 380 case 1: ioapic_mem_writel(pThis, GCPhysAddr, *(uint8_t const *)pv); break; 381 case 2: ioapic_mem_writel(pThis, GCPhysAddr, *(uint16_t const *)pv); break; 382 case 4: ioapic_mem_writel(pThis, GCPhysAddr, *(uint32_t const *)pv); break; 383 384 default: 385 IOAPIC_UNLOCK(pThis); 386 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 387 return VERR_INTERNAL_ERROR; 388 } 398 399 /* 400 * Fetch the value. 401 * 402 * We've told IOM to only give us DWORD accesses. Observations on AMD 403 * indicates that unaligned writes get their missing bytes written as zero. 404 */ 405 Assert(!(GCPhysAddr & 3)); Assert(cb == 4); 406 uint32_t u32Value = *(uint32_t const *)pv; 407 408 /* 409 * The 0xff mask is because we don't really implement the APICBASE register 410 * in the PIIX3, so if the guest tries to relocate the IOAPIC via PIIX3 we 411 * won't know. The I/O APIC address is on the form FEC0xy00h, where xy is 412 * programmable. Masking 0xff means we cover the y. The x would require 413 * reregistering MMIO memory, which means the guest is out of luck there. 414 */ 415 int rc; 416 uint32_t offReg = GCPhysAddr & 0xff; 417 if (offReg == 0) 418 rc = ioapic_IoRegSel_w(pThis, u32Value); 419 else if (offReg == 0x10) 420 rc = ioapic_IoWin_w(pThis, u32Value); 421 else 422 { 423 Log(("ioapicMMIOWrite: Invalid access: offReg=%#x u32Value=%#x\n", offReg, u32Value)); 424 rc = VINF_SUCCESS; 425 } 426 389 427 IOAPIC_UNLOCK(pThis); 390 return VINF_SUCCESS;428 return rc; 391 429 } 392 430 … … 556 594 557 595 /* 596 * Initialize the state data. 597 */ 598 pThis->pDevInsR3 = pDevIns; 599 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 600 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 601 /* (the rest is done by the reset call at the end) */ 602 603 /* PDM provides locking via the IOAPIC helpers. */ 604 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); 605 AssertRCReturn(rc, rc); 606 607 /* 558 608 * Validate and read the configuration. 559 609 */ … … 561 611 562 612 uint32_t cCpus; 563 intrc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1);613 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &cCpus, 1); 564 614 if (RT_FAILURE(rc)) 565 615 return PDMDEV_SET_ERROR(pDevIns, rc, … … 568 618 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 569 619 N_("Configuration error: Max %u CPUs, %u specified"), UINT8_MAX - 1, cCpus); 620 pThis->cCpus = (uint8_t)cCpus; 570 621 571 622 bool fRZEnabled; … … 576 627 577 628 Log(("IOAPIC: cCpus=%u fRZEnabled=%RTbool\n", cCpus, fRZEnabled)); 578 579 /*580 * Initialize the state data.581 */582 pThis->pDevInsR3 = pDevIns;583 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);584 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);585 pThis->cCpus = (uint8_t)cCpus;586 /* (the rest is done by the reset call at the end) */587 588 /* PDM provides locking via the IOAPIC helpers. */589 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));590 AssertRCReturn(rc, rc);591 629 592 630 /* … … 613 651 */ 614 652 rc = PDMDevHlpMMIORegister(pDevIns, UINT32_C(0xfec00000), 0x1000, pThis, 615 IOMMMIO_FLAGS_READ_ PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,653 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, 616 654 ioapicMMIOWrite, ioapicMMIORead, "I/O APIC Memory"); 617 655 if (RT_FAILURE(rc))
Note:
See TracChangeset
for help on using the changeset viewer.