~ubuntu-branches/ubuntu/trusty/virtualbox-ose/trusty

« back to all changes in this revision

Viewing changes to src/VBox/Devices/PC/DevAPIC.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
# pragma warning(disable:4244)
57
57
#endif
58
58
 
 
59
/** The current saved state version.*/
 
60
#define APIC_SAVED_STATE_VERSION            3
 
61
/** The saved state version used by VirtualBox v3 and earlier.
 
62
 * This does not include the config.  */
 
63
#define APIC_SAVED_STATE_VERSION_VBOX_30    2
 
64
/** Some ancient version... */
 
65
#define APIC_SAVED_STATE_VERSION_ANCIENT    1
 
66
 
 
67
 
59
68
/** @def APIC_LOCK
60
69
 * Acquires the PDM lock. */
61
70
#define APIC_LOCK(pThis, rcBusy) \
96
105
    do {                                                  \
97
106
        uint32_t i;                                       \
98
107
        APICState *apic = (dev)->CTX_SUFF(paLapics);      \
99
 
        for (i = 0; i < dev->cCpus; i++)                  \
 
108
        for (i = 0; i < (dev)->cCpus; i++)                  \
100
109
        {                                                 \
101
110
            if (mask & (1 << (apic->id)))                 \
102
111
            {                                             \
149
158
#define APIC_LVT_NB      6
150
159
 
151
160
/* APIC delivery modes */
152
 
#define APIC_DM_FIXED   0
153
 
#define APIC_DM_LOWPRI  1
154
 
#define APIC_DM_SMI     2
155
 
#define APIC_DM_NMI     4
156
 
#define APIC_DM_INIT    5
157
 
#define APIC_DM_SIPI    6
158
 
#define APIC_DM_EXTINT  7
 
161
#define APIC_DM_FIXED   0
 
162
#define APIC_DM_LOWPRI  1
 
163
#define APIC_DM_SMI     2
 
164
#define APIC_DM_NMI     4
 
165
#define APIC_DM_INIT    5
 
166
#define APIC_DM_SIPI    6
 
167
#define APIC_DM_EXTINT  7
159
168
 
160
169
/* APIC destination mode */
161
 
#define APIC_DESTMODE_FLAT      0xf
162
 
#define APIC_DESTMODE_CLUSTER   1
 
170
#define APIC_DESTMODE_FLAT      0xf
 
171
#define APIC_DESTMODE_CLUSTER   1
163
172
 
164
173
#define APIC_TRIGGER_EDGE  0
165
174
#define APIC_TRIGGER_LEVEL 1
166
175
 
167
 
#define APIC_LVT_TIMER_PERIODIC         (1<<17)
168
 
#define APIC_LVT_MASKED                 (1<<16)
169
 
#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
170
 
#define APIC_LVT_REMOTE_IRR             (1<<14)
171
 
#define APIC_INPUT_POLARITY             (1<<13)
172
 
#define APIC_SEND_PENDING               (1<<12)
 
176
#define APIC_LVT_TIMER_PERIODIC         (1<<17)
 
177
#define APIC_LVT_MASKED                 (1<<16)
 
178
#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
 
179
#define APIC_LVT_REMOTE_IRR             (1<<14)
 
180
#define APIC_INPUT_POLARITY             (1<<13)
 
181
#define APIC_SEND_PENDING               (1<<12)
173
182
 
174
 
#define IOAPIC_NUM_PINS                 0x18
 
183
#define IOAPIC_NUM_PINS                 0x18
175
184
 
176
185
#define ESR_ILLEGAL_ADDRESS (1 << 7)
177
186
 
192
201
#ifdef VBOX
193
202
    /* Task priority register (interrupt level) */
194
203
    uint32_t   tpr;
195
 
    /* Logical APIC id */
 
204
    /* Logical APIC id - user programmable */
196
205
    LogApicId  id;
197
 
    /* Physical APIC id */
 
206
    /* Physical APIC id - not visible to user, constant */
198
207
    PhysApicId phys_id;
199
208
    /** @todo: is it logical or physical? Not really used anyway now. */
200
209
    PhysApicId arb_id;
240
249
    /** Timer description timer. */
241
250
    R3PTRTYPE(char *)       pszDesc;
242
251
# ifdef VBOX_WITH_STATISTICS
 
252
#  if HC_ARCH_BITS == 32
 
253
    uint32_t                u32Alignment0;
 
254
#  endif
243
255
    STAMCOUNTER             StatTimerSetInitialCount;
244
256
    STAMCOUNTER             StatTimerSetInitialCountArm;
245
257
    STAMCOUNTER             StatTimerSetInitialCountDisarm;
253
265
# endif
254
266
#endif /* VBOX */
255
267
} APICState;
 
268
#ifdef VBOX
 
269
AssertCompileMemberAlignment(APICState, initial_count_load_time, 8);
 
270
# ifdef VBOX_WITH_STATISTICS
 
271
AssertCompileMemberAlignment(APICState, StatTimerSetInitialCount, 8);
 
272
# endif
 
273
#endif
256
274
 
257
275
struct IOAPICState {
258
276
    uint8_t id;
319
337
    RCPTRTYPE(APICState *)  paLapicsRC;
320
338
    /** The critical section - R3 Ptr. */
321
339
    RCPTRTYPE(PPDMCRITSECT) pCritSectRC;
322
 
    RTRCPTR                 Padding0;
323
340
 
324
341
    /** APIC specification version in this virtual hardware configuration. */
325
342
    PDMAPICVERSION          enmVersion;
329
346
 
330
347
    /** Number of CPUs on the system (same as LAPIC count). */
331
348
    uint32_t                cCpus;
 
349
    /** Whether we've got an IO APIC or not. */
 
350
    bool                    fIoApic;
 
351
    /** Alignment padding. */
 
352
    bool                    afPadding[3];
332
353
 
333
354
# ifdef VBOX_WITH_STATISTICS
334
355
    STAMCOUNTER             StatMMIOReadGC;
338
359
    STAMCOUNTER             StatClearedActiveIrq;
339
360
# endif
340
361
} APICDeviceInfo;
 
362
# ifdef VBOX_WITH_STATISTICS
 
363
AssertCompileMemberAlignment(APICDeviceInfo, StatMMIOReadGC, 8);
 
364
# endif
341
365
#endif /* VBOX */
342
366
 
343
367
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
365
389
PDMBOTHCBDECL(int)  apicBusDeliverCallback(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
366
390
                                           uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
367
391
                                           uint8_t u8TriggerMode);
 
392
PDMBOTHCBDECL(int)  apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level);
368
393
PDMBOTHCBDECL(int)  apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value);
369
394
PDMBOTHCBDECL(int)  apicReadMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value);
370
395
PDMBOTHCBDECL(int)  ioapicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
385
410
static uint32_t apic_get_current_count(APICDeviceInfo* dev, APICState *s);
386
411
static void apicTimerSetInitialCount(APICDeviceInfo *dev, APICState *s, uint32_t initial_count);
387
412
static void apicTimerSetLvt(APICDeviceInfo *dev, APICState *pThis, uint32_t fNew);
 
413
static void apicSendInitIpi(APICDeviceInfo* dev, APICState *s);
388
414
 
389
415
#endif /* VBOX */
390
416
 
421
447
                                               getCpuFromLapic(dev, s));
422
448
}
423
449
 
424
 
DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s)
 
450
DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
425
451
{
426
452
    LogFlow(("apic: clear interrupt flag\n"));
427
 
    dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns),
 
453
    dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns), enmType,
428
454
                                                 getCpuFromLapic(dev, s));
429
455
}
430
456
 
531
557
#ifdef VBOX
532
558
#ifdef IN_RING3
533
559
            foreach_apic(dev, deliver_bitmask,
534
 
                         apic_init_ipi(dev, apic));
 
560
                         apicSendInitIpi(dev, apic));
535
561
            return VINF_SUCCESS;
536
562
#else
537
563
            /* We shall send init IPI only in R3, R0 calls should be
938
964
                            u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
939
965
}
940
966
 
 
967
/**
 
968
 * Local interrupt delivery, for devices attached to the CPU's LINT0/LINT1 pin.
 
969
 * Normally used for 8259A PIC and NMI.
 
970
 */
 
971
PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level)
 
972
{
 
973
    APICDeviceInfo  *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
 
974
    APICState       *s = getLapicById(dev, 0);
 
975
 
 
976
    Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
 
977
    LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x\n", pDevIns, u8Pin));
 
978
 
 
979
    /* If LAPIC is disabled, go straight to the CPU. */
 
980
    if (!(s->spurious_vec & APIC_SV_ENABLE))
 
981
    {
 
982
        LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n"));
 
983
        if (u8Level)
 
984
            cpuSetInterrupt(dev, s, PDMAPICIRQ_EXTINT);
 
985
        else
 
986
            cpuClearInterrupt(dev, s, PDMAPICIRQ_EXTINT);
 
987
 
 
988
        return VINF_SUCCESS;
 
989
    }
 
990
 
 
991
    /* If LAPIC is enabled, interrupts are subject to LVT programming. */
 
992
 
 
993
    /* There are only two local interrupt pins. */
 
994
    AssertMsgReturn(u8Pin <= 1, ("Invalid LAPIC pin %d\n", u8Pin), VERR_INVALID_PARAMETER);
 
995
 
 
996
    /* NB: We currently only deliver local interrupts to the first CPU. In theory they
 
997
     * should be delivered to all CPUs and it is the guest's responsibility to ensure
 
998
     * no more than one CPU has the interrupt unmasked.
 
999
     */
 
1000
    uint32_t    u32Lvec;
 
1001
 
 
1002
    u32Lvec = s->lvt[APIC_LVT_LINT0 + u8Pin];   /* Fetch corresponding LVT entry. */
 
1003
    /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */
 
1004
    if (!(u32Lvec & APIC_LVT_MASKED))
 
1005
    {   uint8_t     u8Delivery;
 
1006
        PDMAPICIRQ  enmType;
 
1007
 
 
1008
        u8Delivery = (u32Lvec >> 8) & 7;
 
1009
        switch (u8Delivery)
 
1010
        {
 
1011
            case APIC_DM_EXTINT:
 
1012
                Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
 
1013
                enmType = PDMAPICIRQ_EXTINT;
 
1014
                /* ExtINT can be both set and cleared, NMI/SMI/INIT can only be set. */
 
1015
                LogFlow(("apicLocalInterrupt: %s ExtINT interrupt\n", u8Level ? "setting" : "clearing"));
 
1016
                if (u8Level)
 
1017
                    cpuSetInterrupt(dev, s, enmType);
 
1018
                else
 
1019
                    cpuClearInterrupt(dev, s, enmType);
 
1020
                return VINF_SUCCESS;
 
1021
            case APIC_DM_NMI:
 
1022
                /* External NMI should be wired to LINT1, but Linux sometimes programs
 
1023
                 * LVT0 to NMI delivery mode as well.
 
1024
                 */
 
1025
                enmType = PDMAPICIRQ_NMI;
 
1026
                /* Currently delivering NMIs through here causes problems with NMI watchdogs
 
1027
                 * on certain Linux kernels, e.g. 64-bit CentOS 5.3. Disable NMIs for now.
 
1028
                 */
 
1029
                return VINF_SUCCESS;
 
1030
            case APIC_DM_SMI:
 
1031
                enmType = PDMAPICIRQ_SMI;
 
1032
                break;
 
1033
            case APIC_DM_FIXED:
 
1034
            {
 
1035
                /** @todo implement APIC_DM_FIXED! */
 
1036
                static unsigned s_c = 0;
 
1037
                if (s_c++ < 5)
 
1038
                    LogRel(("delivery type APIC_DM_FIXED not implemented. u8Pin=%d u8Level=%d", u8Pin, u8Level));
 
1039
                return  VINF_SUCCESS;
 
1040
            }
 
1041
            case APIC_DM_INIT:
 
1042
                /** @todo implement APIC_DM_INIT? */
 
1043
            default:
 
1044
            {
 
1045
                static unsigned s_c = 0;
 
1046
                if (s_c++ < 100)
 
1047
                    AssertLogRelMsgFailed(("delivery type %d not implemented. u8Pin=%d u8Level=%d", u8Delivery, u8Pin, u8Level));
 
1048
                return VERR_INTERNAL_ERROR_4;
 
1049
            }
 
1050
        }
 
1051
        LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
 
1052
        cpuSetInterrupt(dev, s, enmType);
 
1053
    }
 
1054
    return VINF_SUCCESS;
 
1055
}
 
1056
 
941
1057
#endif /* VBOX */
942
1058
 
943
1059
/* return -1 if no bit is set */
1150
1266
    s->initial_count = 0;
1151
1267
    s->initial_count_load_time = 0;
1152
1268
    s->next_time = 0;
 
1269
}
 
1270
 
1153
1271
 
1154
1272
#ifdef VBOX
 
1273
static void apicSendInitIpi(APICDeviceInfo* dev, APICState *s)
 
1274
{
 
1275
    apic_init_ipi(dev, s);
1155
1276
    cpuSendInitIpi(dev, s);
 
1277
}
1156
1278
#endif
1157
 
}
1158
1279
 
1159
1280
/* send a SIPI message to the CPU to start it */
1160
1281
static void apic_startup(APICDeviceInfo* dev, APICState *s, int vector_num)
1850
1971
    int i;
1851
1972
 
1852
1973
#ifdef VBOX
1853
 
    if ((version_id < 1) || (version_id > 2))
1854
 
        return -EINVAL;
1855
 
 
1856
1974
     /* XXX: what if the base changes? (registered memory regions) */
1857
1975
    qemu_get_be32s(f, &s->apicbase);
1858
1976
 
1859
1977
    switch (version_id)
1860
1978
    {
1861
 
        case 1:
 
1979
        case APIC_SAVED_STATE_VERSION_ANCIENT:
1862
1980
        {
1863
1981
            uint8_t val = 0;
1864
1982
            qemu_get_8s(f, &val);
1869
1987
            s->arb_id = val;
1870
1988
            break;
1871
1989
        }
1872
 
        case 2:
 
1990
        case APIC_SAVED_STATE_VERSION:
 
1991
        case APIC_SAVED_STATE_VERSION_VBOX_30:
1873
1992
            qemu_get_be32s(f, &s->id);
1874
1993
            qemu_get_be32s(f, &s->phys_id);
1875
1994
            qemu_get_be32s(f, &s->arb_id);
1876
1995
            break;
 
1996
        default:
 
1997
            return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1877
1998
    }
1878
1999
    qemu_get_be32s(f, &s->tpr);
1879
2000
#else
2340
2461
 
2341
2462
#ifdef IN_RING3
2342
2463
 
 
2464
/* Print a 8-dword LAPIC bit map (256 bits). */
 
2465
static void lapicDumpVec(APICDeviceInfo  *dev, APICState *lapic, PCDBGFINFOHLP pHlp, unsigned start)
 
2466
{
 
2467
    unsigned    i;
 
2468
    uint32_t    val;
 
2469
 
 
2470
    for (i = 0; i < 8; ++i)
 
2471
    {
 
2472
        val = apic_mem_readl(dev, lapic, start + (i << 4));
 
2473
        pHlp->pfnPrintf(pHlp, "%08X", val);
 
2474
    }
 
2475
    pHlp->pfnPrintf(pHlp, "\n");
 
2476
}
 
2477
 
 
2478
/* Print basic LAPIC state. */
 
2479
static DECLCALLBACK(void) lapicInfoBasic(APICDeviceInfo  *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
 
2480
{
 
2481
    uint32_t        val;
 
2482
    unsigned        max_lvt;
 
2483
 
 
2484
    pHlp->pfnPrintf(pHlp, "Local APIC at %08X:\n", lapic->apicbase);
 
2485
    val = apic_mem_readl(dev, lapic, 0x20);
 
2486
    pHlp->pfnPrintf(pHlp, "  LAPIC ID  : %08X\n", val);
 
2487
    pHlp->pfnPrintf(pHlp, "    APIC ID = %02X\n", (val >> 24) & 0xff);
 
2488
    val = apic_mem_readl(dev, lapic, 0x30);
 
2489
    max_lvt = (val >> 16) & 0xff;
 
2490
    pHlp->pfnPrintf(pHlp, "  APIC VER   : %08X\n", val);
 
2491
    pHlp->pfnPrintf(pHlp, "    version  = %02X\n", val & 0xff);
 
2492
    pHlp->pfnPrintf(pHlp, "    lvts     = %d\n", ((val >> 16) & 0xff) + 1);
 
2493
    val = apic_mem_readl(dev, lapic, 0x80);
 
2494
    pHlp->pfnPrintf(pHlp, "  TPR        : %08X\n", val);
 
2495
    pHlp->pfnPrintf(pHlp, "    task pri = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
 
2496
    val = apic_mem_readl(dev, lapic, 0xA0);
 
2497
    pHlp->pfnPrintf(pHlp, "  PPR        : %08X\n", val);
 
2498
    pHlp->pfnPrintf(pHlp, "    cpu pri  = %d/%d\n", (val >> 4) & 0xf, val & 0xf);
 
2499
    val = apic_mem_readl(dev, lapic, 0xD0);
 
2500
    pHlp->pfnPrintf(pHlp, "  LDR       : %08X\n", val);
 
2501
    pHlp->pfnPrintf(pHlp, "    log id  = %02X\n", (val >> 24) & 0xff);
 
2502
    val = apic_mem_readl(dev, lapic, 0xE0);
 
2503
    pHlp->pfnPrintf(pHlp, "  DFR       : %08X\n", val);
 
2504
    val = apic_mem_readl(dev, lapic, 0xF0);
 
2505
    pHlp->pfnPrintf(pHlp, "  SVR       : %08X\n", val);
 
2506
    pHlp->pfnPrintf(pHlp, "    focus   = %s\n", val & (1 << 9) ? "check off" : "check on");
 
2507
    pHlp->pfnPrintf(pHlp, "    lapic   = %s\n", val & (1 << 8) ? "ENABLED" : "DISABLED");
 
2508
    pHlp->pfnPrintf(pHlp, "    vector  = %02X\n", val & 0xff);
 
2509
    pHlp->pfnPrintf(pHlp, "  ISR       : ");
 
2510
    lapicDumpVec(dev, lapic, pHlp, 0x100);
 
2511
    val = get_highest_priority_int(lapic->isr);
 
2512
    pHlp->pfnPrintf(pHlp, "    highest = %02X\n", val == ~0U ? 0 : val);
 
2513
    pHlp->pfnPrintf(pHlp, "  IRR       : ");
 
2514
    lapicDumpVec(dev, lapic, pHlp, 0x200);
 
2515
    val = get_highest_priority_int(lapic->irr);
 
2516
    pHlp->pfnPrintf(pHlp, "    highest = %02X\n", val == ~0U ? 0 : val);
 
2517
    val = apic_mem_readl(dev, lapic, 0x320);
 
2518
}
 
2519
 
 
2520
/* Print the more interesting LAPIC LVT entries. */
 
2521
static DECLCALLBACK(void) lapicInfoLVT(APICDeviceInfo  *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
 
2522
{
 
2523
    uint32_t        val;
 
2524
    static const char *dmodes[] = { "Fixed ", "Reserved", "SMI", "Reserved",
 
2525
                                    "NMI", "INIT", "Reserved", "ExtINT" };
 
2526
 
 
2527
    val = apic_mem_readl(dev, lapic, 0x320);
 
2528
    pHlp->pfnPrintf(pHlp, "  LVT Timer : %08X\n", val);
 
2529
    pHlp->pfnPrintf(pHlp, "    mode    = %s\n", val & (1 << 17) ? "periodic" : "one-shot");
 
2530
    pHlp->pfnPrintf(pHlp, "    mask    = %d\n", (val >> 16) & 1);
 
2531
    pHlp->pfnPrintf(pHlp, "    status  = %s\n", val & (1 << 12) ? "pending" : "idle");
 
2532
    pHlp->pfnPrintf(pHlp, "    vector  = %02X\n", val & 0xff);
 
2533
    val = apic_mem_readl(dev, lapic, 0x350);
 
2534
    pHlp->pfnPrintf(pHlp, "  LVT LINT0 : %08X\n", val);
 
2535
    pHlp->pfnPrintf(pHlp, "    mask    = %d\n", (val >> 16) & 1);
 
2536
    pHlp->pfnPrintf(pHlp, "    trigger = %s\n", val & (1 << 15) ? "level" : "edge");
 
2537
    pHlp->pfnPrintf(pHlp, "    rem irr = %d\n", (val >> 14) & 1);
 
2538
    pHlp->pfnPrintf(pHlp, "    polarty = %d\n", (val >> 13) & 1);
 
2539
    pHlp->pfnPrintf(pHlp, "    status  = %s\n", val & (1 << 12) ? "pending" : "idle");
 
2540
    pHlp->pfnPrintf(pHlp, "    delivry = %s\n", dmodes[(val >> 8) & 7]);
 
2541
    pHlp->pfnPrintf(pHlp, "    vector  = %02X\n", val & 0xff);
 
2542
    val = apic_mem_readl(dev, lapic, 0x360);
 
2543
    pHlp->pfnPrintf(pHlp, "  LVT LINT1 : %08X\n", val);
 
2544
    pHlp->pfnPrintf(pHlp, "    mask    = %d\n", (val >> 16) & 1);
 
2545
    pHlp->pfnPrintf(pHlp, "    trigger = %s\n", val & (1 << 15) ? "level" : "edge");
 
2546
    pHlp->pfnPrintf(pHlp, "    rem irr = %d\n", (val >> 14) & 1);
 
2547
    pHlp->pfnPrintf(pHlp, "    polarty = %d\n", (val >> 13) & 1);
 
2548
    pHlp->pfnPrintf(pHlp, "    status  = %s\n", val & (1 << 12) ? "pending" : "idle");
 
2549
    pHlp->pfnPrintf(pHlp, "    delivry = %s\n", dmodes[(val >> 8) & 7]);
 
2550
    pHlp->pfnPrintf(pHlp, "    vector  = %02X\n", val & 0xff);
 
2551
}
 
2552
 
 
2553
/* Print LAPIC timer state. */
 
2554
static DECLCALLBACK(void) lapicInfoTimer(APICDeviceInfo  *dev, APICState *lapic, PCDBGFINFOHLP pHlp)
 
2555
{
 
2556
    uint32_t        val;
 
2557
    unsigned        divider;
 
2558
 
 
2559
    pHlp->pfnPrintf(pHlp, "Local APIC timer:\n");
 
2560
    val = apic_mem_readl(dev, lapic, 0x380);
 
2561
    pHlp->pfnPrintf(pHlp, "  Initial count : %08X\n", val);
 
2562
    val = apic_mem_readl(dev, lapic, 0x390);
 
2563
    pHlp->pfnPrintf(pHlp, "  Current count : %08X\n", val);
 
2564
    val = apic_mem_readl(dev, lapic, 0x3E0);
 
2565
    pHlp->pfnPrintf(pHlp, "  Divide config : %08X\n", val);
 
2566
    divider = ((val >> 1) & 0x04) | (val & 0x03);
 
2567
    pHlp->pfnPrintf(pHlp, "    divider     = %d\n", divider == 7 ? 1 : 2 << divider);
 
2568
}
 
2569
 
 
2570
/**
 
2571
 * Info handler, device version. Dumps Local APIC(s) state according to given argument.
 
2572
 *
 
2573
 * @param   pDevIns     Device instance which registered the info.
 
2574
 * @param   pHlp        Callback functions for doing output.
 
2575
 * @param   pszArgs     Argument string. Optional.
 
2576
 */
 
2577
static DECLCALLBACK(void) lapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 
2578
{
 
2579
    APICDeviceInfo  *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
 
2580
    APICState       *lapic;
 
2581
 
 
2582
    lapic = getLapic(dev);
 
2583
 
 
2584
    if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
 
2585
    {
 
2586
        lapicInfoBasic(dev, lapic, pHlp);
 
2587
    }
 
2588
    else if (!strcmp(pszArgs, "lvt"))
 
2589
    {
 
2590
        lapicInfoLVT(dev, lapic, pHlp);
 
2591
    }
 
2592
    else if (!strcmp(pszArgs, "timer"))
 
2593
    {
 
2594
        lapicInfoTimer(dev, lapic, pHlp);
 
2595
    }
 
2596
    else
 
2597
    {
 
2598
        pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'lvt', 'timer'.\n");
 
2599
    }
 
2600
}
 
2601
 
 
2602
/**
 
2603
 * @copydoc FNSSMDEVLIVEEXEC
 
2604
 */
 
2605
static DECLCALLBACK(int) apicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
 
2606
{
 
2607
    APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
 
2608
 
 
2609
    SSMR3PutU32( pSSM, pThis->cCpus);
 
2610
    SSMR3PutBool(pSSM, pThis->fIoApic);
 
2611
    SSMR3PutU32( pSSM, pThis->enmVersion);
 
2612
    AssertCompile(PDMAPICVERSION_APIC == 2);
 
2613
 
 
2614
    return VINF_SSM_DONT_CALL_AGAIN;
 
2615
}
 
2616
 
2343
2617
/**
2344
2618
 * @copydoc FNSSMDEVSAVEEXEC
2345
2619
 */
2346
 
static DECLCALLBACK(int) apicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
 
2620
static DECLCALLBACK(int) apicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2347
2621
{
2348
2622
    APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2349
2623
 
 
2624
    /* config */
 
2625
    apicLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
 
2626
 
2350
2627
    /* save all APICs data, @todo: is it correct? */
2351
 
    foreach_apic(dev, 0xffffffff, apic_save(pSSMHandle, apic));
 
2628
    foreach_apic(dev, 0xffffffff, apic_save(pSSM, apic));
2352
2629
 
2353
2630
    return VINF_SUCCESS;
2354
2631
}
2356
2633
/**
2357
2634
 * @copydoc FNSSMDEVLOADEXEC
2358
2635
 */
2359
 
static DECLCALLBACK(int) apicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
 
2636
static DECLCALLBACK(int) apicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2360
2637
{
2361
 
    APICDeviceInfo *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2362
 
    /* load all APICs data, @todo: is it correct? */
2363
 
    foreach_apic(dev, 0xffffffff,
2364
 
                 if (apic_load(pSSMHandle, apic, u32Version))
2365
 
                 {
 
2638
    APICDeviceInfo *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
 
2639
 
 
2640
    if (    uVersion != APIC_SAVED_STATE_VERSION
 
2641
        &&  uVersion != APIC_SAVED_STATE_VERSION_VBOX_30
 
2642
        &&  uVersion != APIC_SAVED_STATE_VERSION_ANCIENT)
 
2643
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
2644
 
 
2645
    /* config */
 
2646
    if (uVersion > APIC_SAVED_STATE_VERSION_VBOX_30) {
 
2647
        uint32_t cCpus;
 
2648
        int rc = SSMR3GetU32(pSSM, &cCpus); AssertRCReturn(rc, rc);
 
2649
        if (cCpus != pThis->cCpus)
 
2650
            return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - cCpus: saved=%#x config=%#x"), cCpus, pThis->cCpus);
 
2651
        bool fIoApic;
 
2652
        rc = SSMR3GetBool(pSSM, &fIoApic); AssertRCReturn(rc, rc);
 
2653
        if (fIoApic != pThis->fIoApic)
 
2654
            return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fIoApic: saved=%RTbool config=%RTbool"), fIoApic, pThis->fIoApic);
 
2655
        uint32_t uApicVersion;
 
2656
        rc = SSMR3GetU32(pSSM, &uApicVersion); AssertRCReturn(rc, rc);
 
2657
        if (uApicVersion != (uint32_t)pThis->enmVersion)
 
2658
            return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - uApicVersion: saved=%#x config=%#x"), uApicVersion, pThis->enmVersion);
 
2659
    }
 
2660
 
 
2661
    if (uPass != SSM_PASS_FINAL)
 
2662
        return VINF_SUCCESS;
 
2663
 
 
2664
    /* load all APICs data */ /** @todo: is it correct? */
 
2665
    foreach_apic(pThis, 0xffffffff,
 
2666
                 if (apic_load(pSSM, apic, uVersion)) {
2366
2667
                      AssertFailed();
2367
2668
                      return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2368
2669
                 }
2385
2686
        APICState *pApic = &dev->CTX_SUFF(paLapics)[i];
2386
2687
        TMTimerStop(pApic->CTX_SUFF(pTimer));
2387
2688
 
2388
 
        /* Do not send an init ipi to the VCPU; we take
2389
 
        * care of the proper init ourselves.
 
2689
        /* Clear LAPIC state as if an INIT IPI was sent. */
2390
2690
        apic_init_ipi(dev, pApic);
2391
 
        */
2392
 
 
2393
 
        /* malc, I've removed the initing duplicated in apic_init_ipi(). This
2394
 
        * arb_id was left over.. */
2395
 
        pApic->arb_id = 0;
 
2691
        /* The IDs are not touched by apic_init_ipi() and must be reset now. */
 
2692
        pApic->arb_id = pApic->id = i;
 
2693
        Assert(pApic->id == pApic->phys_id);    /* The two should match again. */
2396
2694
        /* Reset should re-enable the APIC. */
2397
2695
        pApic->apicbase = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
2398
2696
        if (pApic->phys_id == 0)
2401
2699
        /* Clear any pending APIC interrupt action flag. */
2402
2700
        cpuClearInterrupt(dev, pApic);
2403
2701
    }
 
2702
    /** @todo r=bird: Why is this done everytime, while the constructor first
 
2703
     *        checks the CPUID?  Who is right? */
2404
2704
    dev->pApicHlpR3->pfnChangeFeature(dev->pDevInsR3, dev->enmVersion);
2405
2705
 
2406
2706
    APIC_UNLOCK(dev);
2442
2742
    PDMAPICREG      ApicReg;
2443
2743
    int             rc;
2444
2744
    uint32_t        i;
2445
 
    bool            fIOAPIC;
 
2745
    bool            fIoApic;
2446
2746
    bool            fGCEnabled;
2447
2747
    bool            fR0Enabled;
2448
2748
    APICDeviceInfo  *pThis = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
2463
2763
                              "NumCPUs\0"))
2464
2764
        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2465
2765
 
2466
 
    rc = CFGMR3QueryBoolDef(pCfgHandle, "IOAPIC", &fIOAPIC, true);
 
2766
    rc = CFGMR3QueryBoolDef(pCfgHandle, "IOAPIC", &fIoApic, true);
2467
2767
    if (RT_FAILURE(rc))
2468
2768
        return PDMDEV_SET_ERROR(pDevIns, rc,
2469
2769
                                N_("Configuration error: Failed to read \"IOAPIC\""));
2483
2783
        return PDMDEV_SET_ERROR(pDevIns, rc,
2484
2784
                                N_("Configuration error: Failed to query integer value \"NumCPUs\""));
2485
2785
 
2486
 
    Log(("APIC: cCpus=%d fR0Enabled=%RTbool fGCEnabled=%RTbool fIOAPIC=%RTbool\n", cCpus, fR0Enabled, fGCEnabled, fIOAPIC));
 
2786
    Log(("APIC: cCpus=%d fR0Enabled=%RTbool fGCEnabled=%RTbool fIoApic=%RTbool\n", cCpus, fR0Enabled, fGCEnabled, fIoApic));
2487
2787
 
2488
 
    /* TODO: Current implementation is limited to 32 CPUs due to the use of 32 bits bitmasks. */
 
2788
    /** @todo Current implementation is limited to 32 CPUs due to the use of 32
 
2789
     *        bits bitmasks. */
2489
2790
    if (cCpus > 32)
2490
2791
        return PDMDEV_SET_ERROR(pDevIns, rc,
2491
2792
                                N_("Configuration error: Invalid value for \"NumCPUs\""));
2497
2798
    pThis->pDevInsR0  = PDMDEVINS_2_R0PTR(pDevIns);
2498
2799
    pThis->pDevInsRC  = PDMDEVINS_2_RCPTR(pDevIns);
2499
2800
    pThis->cCpus      = cCpus;
 
2801
    pThis->fIoApic    = fIoApic;
2500
2802
    /* Use PDMAPICVERSION_X2APIC to activate x2APIC mode */
2501
2803
    pThis->enmVersion = PDMAPICVERSION_APIC;
2502
2804
 
2526
2828
    ApicReg.pfnWriteMSRR3           = apicWriteMSR;
2527
2829
    ApicReg.pfnReadMSRR3            = apicReadMSR;
2528
2830
    ApicReg.pfnBusDeliverR3         = apicBusDeliverCallback;
 
2831
    ApicReg.pfnLocalInterruptR3     = apicLocalInterrupt;
2529
2832
    if (fGCEnabled) {
2530
2833
        ApicReg.pszGetInterruptRC   = "apicGetInterrupt";
2531
2834
        ApicReg.pszHasPendingIrqRC  = "apicHasPendingIrq";
2536
2839
        ApicReg.pszWriteMSRRC       = "apicWriteMSR";
2537
2840
        ApicReg.pszReadMSRRC        = "apicReadMSR";
2538
2841
        ApicReg.pszBusDeliverRC     = "apicBusDeliverCallback";
 
2842
        ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
2539
2843
    } else {
2540
2844
        ApicReg.pszGetInterruptRC   = NULL;
2541
2845
        ApicReg.pszHasPendingIrqRC  = NULL;
2546
2850
        ApicReg.pszWriteMSRRC       = NULL;
2547
2851
        ApicReg.pszReadMSRRC        = NULL;
2548
2852
        ApicReg.pszBusDeliverRC     = NULL;
 
2853
        ApicReg.pszLocalInterruptRC = NULL;
2549
2854
    }
2550
2855
    if (fR0Enabled) {
2551
2856
        ApicReg.pszGetInterruptR0   = "apicGetInterrupt";
2557
2862
        ApicReg.pszWriteMSRR0       = "apicWriteMSR";
2558
2863
        ApicReg.pszReadMSRR0        = "apicReadMSR";
2559
2864
        ApicReg.pszBusDeliverR0     = "apicBusDeliverCallback";
 
2865
        ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
2560
2866
    } else {
2561
2867
        ApicReg.pszGetInterruptR0   = NULL;
2562
2868
        ApicReg.pszHasPendingIrqR0  = NULL;
2567
2873
        ApicReg.pszWriteMSRR0       = NULL;
2568
2874
        ApicReg.pszReadMSRR0        = NULL;
2569
2875
        ApicReg.pszBusDeliverR0     = NULL;
 
2876
        ApicReg.pszLocalInterruptR0 = NULL;
2570
2877
    }
2571
2878
 
2572
2879
    Assert(pDevIns->pDevHlpR3->pfnAPICRegister);
2577
2884
    /*
2578
2885
     * The the CPUID feature bit.
2579
2886
     */
 
2887
    /** @todo r=bird: See remark in the apicReset. */
2580
2888
    uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
2581
2889
    PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
2582
2890
    if (u32Eax >= 1) {
2583
 
        if (   fIOAPIC                       /* If IOAPIC is enabled, enable Local APIC in any case */
2584
 
               || (   u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
2585
 
                      && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
2586
 
                      && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
2587
 
               || (   u32Ebx == X86_CPUID_VENDOR_AMD_EBX
2588
 
                      && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
2589
 
                      && u32Edx == X86_CPUID_VENDOR_AMD_EDX   /* AuthenticAMD */)) {
 
2891
        if (   fIoApic                       /* If IOAPIC is enabled, enable Local APIC in any case */
 
2892
            || (   u32Ebx == X86_CPUID_VENDOR_INTEL_EBX
 
2893
                && u32Ecx == X86_CPUID_VENDOR_INTEL_ECX
 
2894
                && u32Edx == X86_CPUID_VENDOR_INTEL_EDX /* GenuineIntel */)
 
2895
            || (   u32Ebx == X86_CPUID_VENDOR_AMD_EBX
 
2896
                && u32Ecx == X86_CPUID_VENDOR_AMD_ECX
 
2897
                && u32Edx == X86_CPUID_VENDOR_AMD_EDX   /* AuthenticAMD */)) {
2590
2898
            LogRel(("Activating Local APIC\n"));
2591
2899
            pThis->pApicHlpR3->pfnChangeFeature(pDevIns, pThis->enmVersion);
2592
2900
        }
2639
2947
    /*
2640
2948
     * Saved state.
2641
2949
     */
2642
 
    rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 2 /* version */,
2643
 
                              sizeof(*pThis), NULL, apicSaveExec, NULL, NULL, apicLoadExec, NULL);
 
2950
    rc = PDMDevHlpSSMRegister3(pDevIns, APIC_SAVED_STATE_VERSION, sizeof(*pThis),
 
2951
                               apicLiveExec, apicSaveExec, apicLoadExec);
2644
2952
    if (RT_FAILURE(rc))
2645
2953
        return rc;
2646
2954
 
 
2955
    /*
 
2956
     * Register debugger info callback.
 
2957
     */
 
2958
    PDMDevHlpDBGFInfoRegister(pDevIns, "lapic", "Display Local APIC state for current CPU. "
 
2959
                              "Recognizes 'basic', 'lvt', 'timer' as arguments, defaulting to 'basic'.", lapicInfo);
 
2960
 
2647
2961
#ifdef VBOX_WITH_STATISTICS
2648
2962
    /*
2649
2963
     * Statistics.
2794
3108
#ifdef IN_RING3
2795
3109
 
2796
3110
/**
 
3111
 * Info handler, device version. Dumps I/O APIC state.
 
3112
 *
 
3113
 * @param   pDevIns     Device instance which registered the info.
 
3114
 * @param   pHlp        Callback functions for doing output.
 
3115
 * @param   pszArgs     Argument string. Optional and specific to the handler.
 
3116
 */
 
3117
static DECLCALLBACK(void) ioapicInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
 
3118
{
 
3119
    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
 
3120
    uint32_t    val;
 
3121
    unsigned    i;
 
3122
    unsigned    max_redir;
 
3123
 
 
3124
    pHlp->pfnPrintf(pHlp, "I/O APIC at %08X:\n", 0xfec00000);
 
3125
    val = s->id << 24;  /* Would be nice to call ioapic_mem_readl() directly, but that's not so simple. */
 
3126
    pHlp->pfnPrintf(pHlp, "  IOAPICID  : %08X\n", val);
 
3127
    pHlp->pfnPrintf(pHlp, "    APIC ID = %02X\n", (val >> 24) & 0xff);
 
3128
    val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16);
 
3129
    max_redir = (val >> 16) & 0xff;
 
3130
    pHlp->pfnPrintf(pHlp, "  IOAPICVER : %08X\n", val);
 
3131
    pHlp->pfnPrintf(pHlp, "    version = %02X\n", val & 0xff);
 
3132
    pHlp->pfnPrintf(pHlp, "    redirs  = %d\n", ((val >> 16) & 0xff) + 1);
 
3133
    val = 0;
 
3134
    pHlp->pfnPrintf(pHlp, "  IOAPICARB : %08X\n", val);
 
3135
    pHlp->pfnPrintf(pHlp, "    arb ID  = %02X\n", (val >> 24) & 0xff);
 
3136
    Assert(sizeof(s->ioredtbl) / sizeof(s->ioredtbl[0]) > max_redir);
 
3137
    pHlp->pfnPrintf(pHlp, "I/O redirection table\n");
 
3138
    pHlp->pfnPrintf(pHlp, " idx dst_mode dst_addr mask trigger rirr polarity dlvr_st dlvr_mode vector\n");
 
3139
    for (i = 0; i <= max_redir; ++i)
 
3140
    {
 
3141
        static const char *dmodes[] = { "Fixed ", "LowPri", "SMI   ", "Resrvd",
 
3142
                                        "NMI   ", "INIT  ", "Resrvd", "ExtINT" };
 
3143
 
 
3144
        pHlp->pfnPrintf(pHlp, "  %02d   %s      %02X     %d    %s   %d   %s  %s     %s   %3d (%016llX)\n",
 
3145
                        i,
 
3146
                        s->ioredtbl[i] & (1 << 11) ? "log " : "phys",           /* dest mode */
 
3147
                        (int)(s->ioredtbl[i] >> 56),                            /* dest addr */
 
3148
                        (int)(s->ioredtbl[i] >> 16) & 1,                        /* mask */
 
3149
                        s->ioredtbl[i] & (1 << 15) ? "level" : "edge ",         /* trigger */
 
3150
                        (int)(s->ioredtbl[i] >> 14) & 1,                        /* remote IRR */
 
3151
                        s->ioredtbl[i] & (1 << 13) ? "activelo" : "activehi",   /* polarity */
 
3152
                        s->ioredtbl[i] & (1 << 12) ? "pend" : "idle",           /* delivery status */
 
3153
                        dmodes[(s->ioredtbl[i] >> 8) & 0x07],                   /* delivery mode */
 
3154
                        (int)s->ioredtbl[i] & 0xff,                             /* vector */
 
3155
                        s->ioredtbl[i]                                          /* entire register */
 
3156
                        );
 
3157
    }
 
3158
}
 
3159
 
 
3160
/**
2797
3161
 * @copydoc FNSSMDEVSAVEEXEC
2798
3162
 */
2799
 
static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
 
3163
static DECLCALLBACK(int) ioapicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2800
3164
{
2801
3165
    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
2802
 
    ioapic_save(pSSMHandle, s);
 
3166
    ioapic_save(pSSM, s);
2803
3167
    return VINF_SUCCESS;
2804
3168
}
2805
3169
 
2806
3170
/**
2807
3171
 * @copydoc FNSSMDEVLOADEXEC
2808
3172
 */
2809
 
static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
 
3173
static DECLCALLBACK(int) ioapicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2810
3174
{
2811
3175
    IOAPICState *s = PDMINS_2_DATA(pDevIns, IOAPICState *);
2812
3176
 
2813
 
    if (ioapic_load(pSSMHandle, s, u32Version)) {
 
3177
    if (ioapic_load(pSSM, s, uVersion)) {
2814
3178
        AssertFailed();
2815
3179
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2816
3180
    }
 
3181
    Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2817
3182
 
2818
3183
    return VINF_SUCCESS;
2819
3184
}
2918
3283
            return rc;
2919
3284
    }
2920
3285
 
2921
 
    rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1 /* version */,
2922
 
                              sizeof(*s), NULL, ioapicSaveExec, NULL, NULL, ioapicLoadExec, NULL);
 
3286
    rc = PDMDevHlpSSMRegister(pDevIns, 1 /* version */, sizeof(*s), ioapicSaveExec, ioapicLoadExec);
2923
3287
    if (RT_FAILURE(rc))
2924
3288
        return rc;
2925
3289
 
 
3290
    /*
 
3291
     * Register debugger info callback.
 
3292
     */
 
3293
    PDMDevHlpDBGFInfoRegister(pDevIns, "ioapic", "Display I/O APIC state.", ioapicInfo);
 
3294
 
2926
3295
#ifdef VBOX_WITH_STATISTICS
2927
3296
    /*
2928
3297
     * Statistics.