VirtualBox

Changeset 37444 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jun 14, 2011 2:34:52 PM (14 years ago)
Author:
vboxsync
Message:

DevACPI: Locking and code cleanup.

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevACPI.cpp

    r37391 r37444  
    55
    66/*
    7  * Copyright (C) 2006-2009 Oracle Corporation
     7 * Copyright (C) 2006-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222#include <VBox/vmm/pdmdev.h>
    2323#include <VBox/vmm/pgm.h>
     24#include <VBox/vmm/dbgftrace.h>
    2425#include <VBox/log.h>
    2526#include <VBox/param.h>
     
    5253*   Defined Constants And Macros                                               *
    5354*******************************************************************************/
     55#ifdef IN_RING3
     56/** Locks the device state, ring-3 only.  */
     57# define DEVACPI_LOCK_R3(a_pThis) \
     58    do { \
     59        int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
     60        AssertRC(rcLock); \
     61    } while (0)
     62#endif
     63/** Unlocks the device state (all contexts). */
     64#define DEVACPI_UNLOCK(a_pThis) \
     65    do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
     66
     67
    5468#define DEBUG_HEX       0x3000
    5569#define DEBUG_CHR       0x3001
     
    198212{
    199213    PCIDevice           dev;
     214    /** Critical section protecting the ACPI state. */
     215    PDMCRITSECT         CritSect;
     216
    200217    uint16_t            pm1a_en;
    201218    uint16_t            pm1a_sts;
     
    205222    uint64_t            u64PmTimerInitial;
    206223    uint64_t            u64PmTimerLastSeen;
    207     PTMTIMERR3          tsR3;
    208     PTMTIMERR0          tsR0;
    209     PTMTIMERRC          tsRC;
     224    PTMTIMERR3          pPmTimerR3;
     225    PTMTIMERR0          pPmTimerR0;
     226    PTMTIMERRC          pPmTimerRC;
    210227
    211228    uint32_t            gpe0_en;
     
    693710*******************************************************************************/
    694711RT_C_DECLS_BEGIN
    695 PDMBOTHCBDECL(int) acpiPMTmrRead(       PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
     712PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
     713RT_C_DECLS_END
    696714#ifdef IN_RING3
    697 PDMBOTHCBDECL(int) acpiPm1aEnRead(      PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    698 PDMBOTHCBDECL(int) acpiPM1aEnWrite(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    699 PDMBOTHCBDECL(int) acpiPm1aStsRead(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    700 PDMBOTHCBDECL(int) acpiPM1aStsWrite(    PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    701 PDMBOTHCBDECL(int) acpiPm1aCtlRead(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    702 PDMBOTHCBDECL(int) acpiPM1aCtlWrite(    PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    703 PDMBOTHCBDECL(int) acpiSmiWrite(        PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    704 PDMBOTHCBDECL(int) acpiBatIndexWrite(   PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    705 PDMBOTHCBDECL(int) acpiBatDataRead(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    706 PDMBOTHCBDECL(int) acpiSysInfoDataRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    707 PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    708 PDMBOTHCBDECL(int) acpiGpe0EnRead(      PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    709 PDMBOTHCBDECL(int) acpiGpe0EnWrite(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    710 PDMBOTHCBDECL(int) acpiGpe0StsRead(     PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
    711 PDMBOTHCBDECL(int) acpiGpe0StsWrite(    PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    712 PDMBOTHCBDECL(int) acpiResetWrite(      PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
     715static int acpiPlantTables(ACPIState *s);
     716#endif
     717
     718#ifdef IN_RING3
     719
     720/* SCI IRQ */
     721DECLINLINE(void) acpiSetIrq(ACPIState *s, int level)
     722{
     723    if (s->pm1a_ctl & SCI_EN)
     724        PDMDevHlpPCISetIrq(s->pDevIns, -1, level);
     725}
     726
     727DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
     728{
     729    return en & ~(RSR_EN | IGN_EN);
     730}
     731
     732DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
     733{
     734    return sts & ~(RSR_STS | IGN_STS);
     735}
     736
     737DECLINLINE(int) pm1a_level(ACPIState *s)
     738{
     739    return (pm1a_pure_en(s->pm1a_en) & pm1a_pure_sts(s->pm1a_sts)) != 0;
     740}
     741
     742DECLINLINE(int) gpe0_level(ACPIState *s)
     743{
     744    return (s->gpe0_en & s->gpe0_sts) != 0;
     745}
     746
     747/**
     748 * Used by acpiPM1aStsWrite, acpiPM1aEnWrite, acpiPmTimer,
     749 * acpiPort_PowerBuffonPress and acpiPort_SleepButtonPress to
     750 * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
     751 *
     752 * Caller must hold the state lock.
     753 *
     754 * @param   pThis       The ACPI instance.
     755 * @param   sts         The new GPE0.STS value.
     756 * @param   en          The new GPE0.EN value.
     757 */
     758static void update_pm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
     759{
     760    Assert(PDMCritSectIsOwner(&pThis->CritSect));
     761
     762    if (gpe0_level(pThis))
     763        return;
     764
     765    int const old_level = pm1a_level(pThis);
     766    int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
     767
     768    Log(("update_pm1a() old=%x new=%x\n", old_level, new_level));
     769
     770    pThis->pm1a_en = en;
     771    pThis->pm1a_sts = sts;
     772
     773    if (new_level != old_level)
     774        acpiSetIrq(pThis, new_level);
     775}
     776
     777/**
     778 * Used by acpiGpe0StsWrite, acpiGpe0EnWrite, acpiAttach and acpiDetach to
     779 * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
     780 *
     781 * Caller must hold the state lock.
     782 *
     783 * @param   pThis       The ACPI instance.
     784 * @param   sts         The new GPE0.STS value.
     785 * @param   en          The new GPE0.EN value.
     786 */
     787static void update_gpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
     788{
     789    Assert(PDMCritSectIsOwner(&pThis->CritSect));
     790
     791    if (pm1a_level(pThis))
     792        return;
     793
     794    int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
     795    int const new_level = (en & sts) != 0;
     796
     797    pThis->gpe0_en  = en;
     798    pThis->gpe0_sts = sts;
     799
     800    if (new_level != old_level)
     801        acpiSetIrq(pThis, new_level);
     802}
     803
     804/**
     805 * Used by acpiPM1aCtlWrite to power off the VM.
     806 *
     807 * @param   pThis   The ACPI instance.
     808 * @returns Strict VBox status code.
     809 */
     810static int acpiPowerOff(ACPIState *pThis)
     811{
     812    int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
     813    if (RT_FAILURE(rc))
     814        AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
     815    return rc;
     816}
     817
     818/**
     819 * Used by acpiPM1aCtlWrite to put the VM to sleep.
     820 *
     821 * @param   pThis   The ACPI instance.
     822 * @returns Strict VBox status code.
     823 */
     824static int acpiSleep(ACPIState *pThis)
     825{
     826    /* We must set WAK_STS on resume (includes restore) so the guest knows that
     827       we've woken up and can continue executing code.  The guest is probably
     828       reading the PMSTS register in a loop to check this. */
     829    int rc;
     830    pThis->fSetWakeupOnResume = true;
     831    if (pThis->fSuspendToSavedState)
     832    {
     833        rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
     834        if (rc != VERR_NOT_SUPPORTED)
     835            AssertRC(rc);
     836        else
     837        {
     838            LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
     839            rc = PDMDevHlpVMSuspend(pThis->pDevIns);
     840            AssertRC(rc);
     841        }
     842    }
     843    else
     844    {
     845        rc = PDMDevHlpVMSuspend(pThis->pDevIns);
     846        AssertRC(rc);
     847    }
     848    return rc;
     849}
     850
     851
     852/**
     853 * @interface_method_impl{PDMIACPIPORT,pfnPowerButtonPress}
     854 */
     855static DECLCALLBACK(int) acpiPort_PowerButtonPress(PPDMIACPIPORT pInterface)
     856{
     857    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     858    DEVACPI_LOCK_R3(pThis);
     859
     860    Log(("acpiPort_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
     861    pThis->fPowerButtonHandled = false;
     862    update_pm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
     863
     864    DEVACPI_UNLOCK(pThis);
     865    return VINF_SUCCESS;
     866}
     867
     868/**
     869 * @interface_method_impl{PDMIACPIPORT,pfnGetPowerButtonHandled}
     870 */
     871static DECLCALLBACK(int) acpiPort_GetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
     872{
     873    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     874    DEVACPI_LOCK_R3(pThis);
     875
     876    *pfHandled = pThis->fPowerButtonHandled;
     877
     878    DEVACPI_UNLOCK(pThis);
     879    return VINF_SUCCESS;
     880}
     881
     882/**
     883 * @interface_method_impl{PDMIACPIPORT,pfnGetGuestEnteredACPIMode, Check if the
     884 *                       Guest entered into G0 (working) or G1 (sleeping)}
     885 */
     886static DECLCALLBACK(int) acpiPort_GetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
     887{
     888    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     889    DEVACPI_LOCK_R3(pThis);
     890
     891    *pfEntered = (pThis->pm1a_ctl & SCI_EN) != 0;
     892
     893    DEVACPI_UNLOCK(pThis);
     894    return VINF_SUCCESS;
     895}
     896
     897/**
     898 * @interface_method_impl{PDMIACPIPORT,pfnGetCpuStatus}
     899 */
     900static DECLCALLBACK(int) acpiPort_GetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
     901{
     902    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     903    DEVACPI_LOCK_R3(pThis);
     904
     905    *pfLocked = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, uCpu);
     906
     907    DEVACPI_UNLOCK(pThis);
     908    return VINF_SUCCESS;
     909}
     910
     911/**
     912 * Send an ACPI sleep button event.
     913 *
     914 * @returns VBox status code
     915 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     916 */
     917static DECLCALLBACK(int) acpiPort_SleepButtonPress(PPDMIACPIPORT pInterface)
     918{
     919    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
     920    DEVACPI_LOCK_R3(pThis);
     921
     922    update_pm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
     923
     924    DEVACPI_UNLOCK(pThis);
     925    return VINF_SUCCESS;
     926}
     927
     928/**
     929 * Used by acpiPmTimer to re-arm the PM timer.
     930 *
     931 * The caller is expected to either hold the clock lock or to have made sure
     932 * the VM is resetting or loading state.
     933 *
     934 * @param   pThis               The ACPI instance.
     935 * @param   uNow                The current time.
     936 */
     937static void acpiPmTimerReset(ACPIState *pThis, uint64_t uNow)
     938{
     939    uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
     940    uint64_t uInterval  = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
     941    TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
     942    Log(("acpi: uInterval = %RU64\n", uInterval));
     943}
     944
     945/**
     946 * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
     947 */
     948static DECLCALLBACK(void) acpiPmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     949{
     950    ACPIState *pThis = (ACPIState *)pvUser;
     951    Assert(TMTimerIsLockOwner(pThis->pPmTimerR3));
     952
     953    DEVACPI_LOCK_R3(pThis);
     954    Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
     955         pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
     956         pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
     957    update_pm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
     958    DEVACPI_UNLOCK(pThis);
     959
     960    acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
     961}
     962
     963/**
     964 * _BST method - used by acpiBatDataRead to implement BAT_STATUS_STATE and
     965 * acpiLoadState.
     966 *
     967 * @returns VINF_SUCCESS.
     968 * @param   pThis           The ACPI instance.
     969 */
     970static int acpiFetchBatteryStatus(ACPIState *pThis)
     971{
     972    uint32_t           *p = pThis->au8BatteryInfo;
     973    bool               fPresent;              /* battery present? */
     974    PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
     975    PDMACPIBATSTATE    hostBatteryState;      /* bitfield */
     976    uint32_t           hostPresentRate;       /* 0..1000 */
     977    int                rc;
     978
     979    if (!pThis->pDrv)
     980        return VINF_SUCCESS;
     981    rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
     982                                            &hostBatteryState, &hostPresentRate);
     983    AssertRC(rc);
     984
     985    /* default values */
     986    p[BAT_STATUS_STATE]              = hostBatteryState;
     987    p[BAT_STATUS_PRESENT_RATE]       = hostPresentRate == ~0U ? 0xFFFFFFFF
     988                                                              : hostPresentRate * 50;  /* mW */
     989    p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
     990    p[BAT_STATUS_PRESENT_VOLTAGE]    = 10000; /* mV */
     991
     992    /* did we get a valid battery state? */
     993    if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
     994        p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
     995    if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
     996        p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
     997
     998    return VINF_SUCCESS;
     999}
     1000
     1001/**
     1002 * _BIF method - used by acpiBatDataRead to implement BAT_INFO_UNITS and
     1003 * acpiLoadState.
     1004 *
     1005 * @returns VINF_SUCCESS.
     1006 * @param   pThis           The ACPI instance.
     1007 */
     1008static int acpiFetchBatteryInfo(ACPIState *pThis)
     1009{
     1010    uint32_t *p = pThis->au8BatteryInfo;
     1011
     1012    p[BAT_INFO_UNITS]                      = 0;     /* mWh */
     1013    p[BAT_INFO_DESIGN_CAPACITY]            = 50000; /* mWh */
     1014    p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY]  = 50000; /* mWh */
     1015    p[BAT_INFO_TECHNOLOGY]                 = BAT_TECH_PRIMARY;
     1016    p[BAT_INFO_DESIGN_VOLTAGE]             = 10000; /* mV */
     1017    p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100;   /* mWh */
     1018    p[BAT_INFO_DESIGN_CAPACITY_OF_LOW]     = 50;    /* mWh */
     1019    p[BAT_INFO_CAPACITY_GRANULARITY_1]     = 1;     /* mWh */
     1020    p[BAT_INFO_CAPACITY_GRANULARITY_2]     = 1;     /* mWh */
     1021
     1022    return VINF_SUCCESS;
     1023}
     1024
     1025/**
     1026 * The _STA method - used by acpiBatDataRead to implement BAT_DEVICE_STATUS.
     1027 *
     1028 * @returns status mask or 0.
     1029 * @param   pThis           The ACPI instance.
     1030 */
     1031static uint32_t acpiGetBatteryDeviceStatus(ACPIState *pThis)
     1032{
     1033    bool               fPresent;              /* battery present? */
     1034    PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
     1035    PDMACPIBATSTATE    hostBatteryState;      /* bitfield */
     1036    uint32_t           hostPresentRate;       /* 0..1000 */
     1037    int                rc;
     1038
     1039    if (!pThis->pDrv)
     1040        return 0;
     1041    rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
     1042                                            &hostBatteryState, &hostPresentRate);
     1043    AssertRC(rc);
     1044
     1045    return fPresent
     1046        ?   STA_DEVICE_PRESENT_MASK                     /* present */
     1047          | STA_DEVICE_ENABLED_MASK                     /* enabled and decodes its resources */
     1048          | STA_DEVICE_SHOW_IN_UI_MASK                  /* should be shown in UI */
     1049          | STA_DEVICE_FUNCTIONING_PROPERLY_MASK        /* functioning properly */
     1050          | STA_BATTERY_PRESENT_MASK                    /* battery is present */
     1051        : 0;                                            /* device not present */
     1052}
     1053
     1054/**
     1055 * Used by acpiBatDataRead to implement BAT_POWER_SOURCE.
     1056 *
     1057 * @returns status.
     1058 * @param   pThis           The ACPI instance.
     1059 */
     1060static uint32_t acpiGetPowerSource(ACPIState *pThis)
     1061{
     1062    /* query the current power source from the host driver */
     1063    if (!pThis->pDrv)
     1064        return AC_ONLINE;
     1065
     1066    PDMACPIPOWERSOURCE ps;
     1067    int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
     1068    AssertRC(rc);
     1069    return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
     1070}
     1071
     1072/**
     1073 * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
     1074 */
     1075PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1076{
     1077    Log(("acpiBatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
     1078    if (cb != 4)
     1079        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1080
     1081    ACPIState *pThis = (ACPIState *)pvUser;
     1082    DEVACPI_LOCK_R3(pThis);
     1083
     1084    u32 >>= pThis->u8IndexShift;
     1085    /* see comment at the declaration of u8IndexShift */
     1086    if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
     1087    {
     1088        pThis->u8IndexShift = 2;
     1089        u32 >>= 2;
     1090    }
     1091    Assert(u32 < BAT_INDEX_LAST);
     1092    pThis->uBatteryIndex = u32;
     1093
     1094    DEVACPI_UNLOCK(pThis);
     1095    return VINF_SUCCESS;
     1096}
     1097
     1098/**
     1099 * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
     1100 */
     1101PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1102{
     1103    if (cb != 4)
     1104        return VERR_IOM_IOPORT_UNUSED;
     1105
     1106    ACPIState *pThis = (ACPIState *)pvUser;
     1107    DEVACPI_LOCK_R3(pThis);
     1108
     1109    int rc = VINF_SUCCESS;
     1110    switch (pThis->uBatteryIndex)
     1111    {
     1112        case BAT_STATUS_STATE:
     1113            acpiFetchBatteryStatus(pThis);
     1114            /* fall thru */
     1115        case BAT_STATUS_PRESENT_RATE:
     1116        case BAT_STATUS_REMAINING_CAPACITY:
     1117        case BAT_STATUS_PRESENT_VOLTAGE:
     1118            *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
     1119            break;
     1120
     1121        case BAT_INFO_UNITS:
     1122            acpiFetchBatteryInfo(pThis);
     1123            /* fall thru */
     1124        case BAT_INFO_DESIGN_CAPACITY:
     1125        case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
     1126        case BAT_INFO_TECHNOLOGY:
     1127        case BAT_INFO_DESIGN_VOLTAGE:
     1128        case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
     1129        case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
     1130        case BAT_INFO_CAPACITY_GRANULARITY_1:
     1131        case BAT_INFO_CAPACITY_GRANULARITY_2:
     1132            *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
     1133            break;
     1134
     1135        case BAT_DEVICE_STATUS:
     1136            *pu32 = acpiGetBatteryDeviceStatus(pThis);
     1137            break;
     1138
     1139        case BAT_POWER_SOURCE:
     1140            *pu32 = acpiGetPowerSource(pThis);
     1141            break;
     1142
     1143        default:
     1144            rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
     1145            *pu32 = UINT32_MAX;
     1146            break;
     1147    }
     1148
     1149    DEVACPI_UNLOCK(pThis);
     1150    return rc;
     1151}
     1152
     1153/**
     1154 * @callback_method_impl{FNIOMIOPORTOUT, System info index}
     1155 */
     1156PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1157{
     1158    Log(("acpiSysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
     1159    if (cb != 4)
     1160        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1161
     1162    ACPIState *pThis = (ACPIState *)pvUser;
     1163    DEVACPI_LOCK_R3(pThis);
     1164
     1165    if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
     1166        pThis->uSystemInfoIndex = u32;
     1167    else
     1168    {
     1169        /* see comment at the declaration of u8IndexShift */
     1170        if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
     1171        {
     1172            if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
     1173                pThis->u8IndexShift = 2;
     1174        }
     1175
     1176        u32 >>= pThis->u8IndexShift;
     1177        Assert(u32 < SYSTEM_INFO_INDEX_END);
     1178        pThis->uSystemInfoIndex = u32;
     1179    }
     1180
     1181    DEVACPI_UNLOCK(pThis);
     1182    return VINF_SUCCESS;
     1183}
     1184
     1185/**
     1186 * @callback_method_impl{FNIOMIOPORTIN, System info data}
     1187 */
     1188PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1189{
     1190    if (cb != 4)
     1191        return VERR_IOM_IOPORT_UNUSED;
     1192
     1193    ACPIState *pThis = (ACPIState *)pvUser;
     1194    DEVACPI_LOCK_R3(pThis);
     1195
     1196    int rc = VINF_SUCCESS;
     1197    unsigned const uSystemInfoIndex = pThis->uSystemInfoIndex;
     1198    switch (uSystemInfoIndex)
     1199    {
     1200        case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
     1201            *pu32 = pThis->cbRamLow;
     1202            break;
     1203
     1204        case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
     1205            *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
     1206            Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
     1207            break;
     1208
     1209        case SYSTEM_INFO_INDEX_USE_IOAPIC:
     1210            *pu32 = pThis->u8UseIOApic;
     1211            break;
     1212
     1213        case SYSTEM_INFO_INDEX_HPET_STATUS:
     1214            *pu32 = pThis->fUseHpet
     1215                  ? (  STA_DEVICE_PRESENT_MASK
     1216                     | STA_DEVICE_ENABLED_MASK
     1217                     | STA_DEVICE_SHOW_IN_UI_MASK
     1218                     | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
     1219                  : 0;
     1220            break;
     1221
     1222        case SYSTEM_INFO_INDEX_SMC_STATUS:
     1223            *pu32 = pThis->fUseSmc
     1224                  ? (  STA_DEVICE_PRESENT_MASK
     1225                     | STA_DEVICE_ENABLED_MASK
     1226                     /* no need to show this device in the UI */
     1227                     | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
     1228                  : 0;
     1229            break;
     1230
     1231        case SYSTEM_INFO_INDEX_FDC_STATUS:
     1232            *pu32 = pThis->fUseFdc
     1233                  ? (  STA_DEVICE_PRESENT_MASK
     1234                     | STA_DEVICE_ENABLED_MASK
     1235                     | STA_DEVICE_SHOW_IN_UI_MASK
     1236                     | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
     1237                  : 0;
     1238            break;
     1239
     1240        case SYSTEM_INFO_INDEX_NIC_ADDRESS:
     1241            *pu32 = pThis->u32NicPciAddress;
     1242            break;
     1243
     1244        case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
     1245            *pu32 = pThis->u32AudioPciAddress;
     1246            break;
     1247
     1248        case SYSTEM_INFO_INDEX_POWER_STATES:
     1249            *pu32 = RT_BIT(0) | RT_BIT(5);  /* S1 and S5 always exposed */
     1250            if (pThis->fS1Enabled)          /* Optionally expose S1 and S4 */
     1251                *pu32 |= RT_BIT(1);
     1252            if (pThis->fS4Enabled)
     1253                *pu32 |= RT_BIT(4);
     1254            break;
     1255
     1256       case SYSTEM_INFO_INDEX_IOC_ADDRESS:
     1257            *pu32 = pThis->u32IocPciAddress;
     1258            break;
     1259
     1260        case SYSTEM_INFO_INDEX_HBC_ADDRESS:
     1261            *pu32 = pThis->u32HbcPciAddress;
     1262            break;
     1263
     1264        case SYSTEM_INFO_INDEX_PCI_BASE:
     1265            /** @todo couldn't MCFG be in 64-bit range? */
     1266            Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
     1267            *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
     1268            break;
     1269
     1270        case SYSTEM_INFO_INDEX_PCI_LENGTH:
     1271            /** @todo couldn't MCFG be in 64-bit range? */
     1272            Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
     1273            *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
     1274            break;
     1275
     1276        /* This is only for compatibility with older saved states that
     1277           may include ACPI code that read these values.  Legacy is
     1278           a wonderful thing, isn't it? :-) */
     1279        case SYSTEM_INFO_INDEX_CPU0_STATUS:
     1280        case SYSTEM_INFO_INDEX_CPU1_STATUS:
     1281        case SYSTEM_INFO_INDEX_CPU2_STATUS:
     1282        case SYSTEM_INFO_INDEX_CPU3_STATUS:
     1283            *pu32 = (   pThis->fShowCpu
     1284                     && pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < pThis->cCpus
     1285                     && VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached,
     1286                                            pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS) )
     1287                  ? (  STA_DEVICE_PRESENT_MASK
     1288                     | STA_DEVICE_ENABLED_MASK
     1289                     | STA_DEVICE_SHOW_IN_UI_MASK
     1290                     | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
     1291                  : 0;
     1292            break;
     1293
     1294        case SYSTEM_INFO_INDEX_RTC_STATUS:
     1295            *pu32 = pThis->fShowRtc
     1296                  ? (  STA_DEVICE_PRESENT_MASK
     1297                     | STA_DEVICE_ENABLED_MASK
     1298                     | STA_DEVICE_SHOW_IN_UI_MASK
     1299                     | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
     1300                  : 0;
     1301            break;
     1302
     1303        case SYSTEM_INFO_INDEX_CPU_LOCKED:
     1304            if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
     1305            {
     1306                *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
     1307                pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
     1308            }
     1309            else
     1310            {
     1311                rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
     1312                                       pThis->idCpuLockCheck);
     1313                /* Always return locked status just to be safe */
     1314                *pu32 = 1;
     1315            }
     1316            break;
     1317
     1318        case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
     1319            *pu32 = pThis->u32CpuEventType;
     1320            break;
     1321
     1322        case SYSTEM_INFO_INDEX_CPU_EVENT:
     1323            *pu32 = pThis->u32CpuEvent;
     1324            break;
     1325
     1326        case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
     1327            *pu32 = pThis->uSerial0IoPortBase;
     1328            break;
     1329
     1330        case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
     1331            *pu32 = pThis->uSerial0Irq;
     1332            break;
     1333
     1334        case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
     1335            *pu32 = pThis->uSerial1IoPortBase;
     1336            break;
     1337
     1338        case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
     1339            *pu32 = pThis->uSerial1Irq;
     1340            break;
     1341
     1342        case SYSTEM_INFO_INDEX_END:
     1343            /** @todo why isn't this setting any output value?  */
     1344            break;
     1345
     1346        /* Solaris 9 tries to read from this index */
     1347        case SYSTEM_INFO_INDEX_INVALID:
     1348            *pu32 = 0;
     1349            break;
     1350
     1351        default:
     1352            *pu32 = UINT32_MAX;
     1353            rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
     1354            break;
     1355    }
     1356
     1357    DEVACPI_UNLOCK(pThis);
     1358    Log(("acpiSysInfoDataRead: idx=%d val=%#x (%d) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
     1359    return rc;
     1360}
     1361
     1362/**
     1363 * @callback_method_impl{FNIOMIOPORTOUT, System info data}
     1364 */
     1365PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1366{
     1367    ACPIState *pThis = (ACPIState *)pvUser;
     1368    if (cb != 4)
     1369        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
     1370
     1371    DEVACPI_LOCK_R3(pThis);
     1372    Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
     1373
     1374    int rc = VINF_SUCCESS;
     1375    switch (pThis->uSystemInfoIndex)
     1376    {
     1377        case SYSTEM_INFO_INDEX_INVALID:
     1378            AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
     1379            pThis->u8IndexShift = 0;
     1380            break;
     1381
     1382        case SYSTEM_INFO_INDEX_VALID:
     1383            AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
     1384            pThis->u8IndexShift = 2;
     1385            break;
     1386
     1387        case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
     1388            pThis->idCpuLockCheck = u32;
     1389            break;
     1390
     1391        case SYSTEM_INFO_INDEX_CPU_LOCKED:
     1392            if (u32 < pThis->cCpus)
     1393                VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
     1394            else
     1395                LogRel(("ACPI: CPU %u does not exist\n", u32));
     1396            break;
     1397
     1398        default:
     1399            rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
     1400            break;
     1401    }
     1402
     1403    DEVACPI_UNLOCK(pThis);
     1404    return rc;
     1405}
     1406
     1407/**
     1408 * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
     1409 */
     1410PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1411{
     1412    if (cb != 2)
     1413        return VERR_IOM_IOPORT_UNUSED;
     1414
     1415    ACPIState *pThis = (ACPIState *)pvUser;
     1416    DEVACPI_LOCK_R3(pThis);
     1417
     1418    *pu32 = pThis->pm1a_en;
     1419
     1420    DEVACPI_UNLOCK(pThis);
     1421    Log(("acpiPm1aEnRead -> %#x\n", *pu32));
     1422    return VINF_SUCCESS;
     1423}
     1424
     1425/**
     1426 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
     1427 */
     1428PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1429{
     1430    if (cb != 2 && cb != 4)
     1431        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1432
     1433    ACPIState *pThis = (ACPIState *)pvUser;
     1434    DEVACPI_LOCK_R3(pThis);
     1435
     1436    Log(("acpiPM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
     1437    u32 &= ~(RSR_EN | IGN_EN);
     1438    u32 &= 0xffff;
     1439    update_pm1a(pThis, pThis->pm1a_sts, u32);
     1440
     1441    DEVACPI_UNLOCK(pThis);
     1442    return VINF_SUCCESS;
     1443}
     1444
     1445/**
     1446 * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
     1447 */
     1448PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1449{
     1450    if (cb != 2)
     1451    {
     1452        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
     1453        return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
     1454    }
     1455
     1456    ACPIState *pThis = (ACPIState *)pvUser;
     1457    DEVACPI_LOCK_R3(pThis);
     1458
     1459    *pu32 = pThis->pm1a_sts;
     1460
     1461    DEVACPI_UNLOCK(pThis);
     1462    Log(("acpiPm1aStsRead: %#x\n", *pu32));
     1463    return VINF_SUCCESS;
     1464}
     1465
     1466/**
     1467 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
     1468 */
     1469PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1470{
     1471    if (cb != 2 && cb != 4)
     1472        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1473
     1474    ACPIState *pThis = (ACPIState *)pvUser;
     1475    DEVACPI_LOCK_R3(pThis);
     1476
     1477    Log(("acpiPM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
     1478    u32 &= 0xffff;
     1479    if (u32 & PWRBTN_STS)
     1480        pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
     1481    u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
     1482    update_pm1a(pThis, u32, pThis->pm1a_en);
     1483
     1484    DEVACPI_UNLOCK(pThis);
     1485    return VINF_SUCCESS;
     1486}
     1487
     1488/**
     1489 * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
     1490 */
     1491PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1492{
     1493    if (cb != 2)
     1494    {
     1495        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
     1496        return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
     1497    }
     1498
     1499    ACPIState *pThis = (ACPIState *)pvUser;
     1500    DEVACPI_LOCK_R3(pThis);
     1501
     1502    *pu32 = pThis->pm1a_ctl;
     1503
     1504    DEVACPI_UNLOCK(pThis);
     1505    Log(("acpiPm1aCtlRead: %#x\n", *pu32));
     1506    return VINF_SUCCESS;
     1507}
     1508
     1509/**
     1510 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
     1511 */
     1512PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1513{
     1514    if (cb != 2 && cb != 4)
     1515        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1516
     1517    ACPIState *pThis = (ACPIState *)pvUser;
     1518    DEVACPI_LOCK_R3(pThis);
     1519
     1520    Log(("acpiPM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
     1521    u32 &= 0xffff;
     1522    pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
     1523
     1524    int rc = VINF_SUCCESS;
     1525    uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
     1526    if (uSleepState != pThis->uSleepState)
     1527    {
     1528        pThis->uSleepState = uSleepState;
     1529        switch (uSleepState)
     1530        {
     1531            case 0x00:                  /* S0 */
     1532                break;
     1533
     1534            case 0x01:                  /* S1 */
     1535                if (pThis->fS1Enabled)
     1536                {
     1537                    LogRel(("Entering S1 power state (powered-on suspend)\n"));
     1538                    rc = acpiSleep(pThis);
     1539                    break;
     1540                }
     1541                LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
     1542                /* fall thru */
     1543
     1544            case 0x04:                  /* S4 */
     1545                if (pThis->fS4Enabled)
     1546                {
     1547                    LogRel(("Entering S4 power state (suspend to disk)\n"));
     1548                    rc = acpiPowerOff(pThis);/* Same behavior as S5 */
     1549                    break;
     1550                }
     1551                LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
     1552                /* fall thru */
     1553
     1554            case 0x05:                  /* S5 */
     1555                LogRel(("Entering S5 power state (power down)\n"));
     1556                rc = acpiPowerOff(pThis);
     1557                break;
     1558
     1559            default:
     1560                rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
     1561                break;
     1562        }
     1563    }
     1564
     1565    DEVACPI_UNLOCK(pThis);
     1566    Log(("acpiPM1aCtlWrite: rc=%Rrc\n", rc));
     1567    return rc;
     1568}
     1569
     1570#endif /* IN_RING3 */
     1571
     1572/**
     1573 * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
     1574 *
     1575 * @remarks Only I/O port currently implemented in all contexts.
     1576 */
     1577PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1578{
     1579    if (cb != 4)
     1580        return VERR_IOM_IOPORT_UNUSED;
     1581
     1582    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     1583
     1584    /*
     1585     * We use the clock lock to serialize access to u64PmTimerInitial and to
     1586     * make sure we get a reliable time from the clock.
     1587     */
     1588    int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_HC_IOPORT_READ);
     1589    if (rc == VINF_SUCCESS)
     1590    {
     1591        uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
     1592        uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
     1593
     1594        /*
     1595         * Make 100% sure time doesn't go backwards.
     1596         */
     1597        uint64_t u64Seen;
     1598        do
     1599        {
     1600            u64Seen = ASMAtomicReadU64(&pThis->u64PmTimerLastSeen);
     1601            if (u64Now < u64Seen)
     1602            {
     1603#ifdef DEBUG
     1604                DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi bad");
     1605# if 0
     1606                RTTraceBufDisable(DBGFTRACE_PDM_TRACEBUF(pDevIns));
     1607                AssertFailed();
     1608# endif
     1609#endif
     1610                u64Now = u64Seen + 1;
     1611            }
     1612        } while (!ASMAtomicCmpXchgU64(&pThis->u64PmTimerLastSeen, u64Now, u64Seen));
     1613
     1614        TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
     1615
     1616        /*
     1617         * Calculate the return value.
     1618         */
     1619        DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
     1620        uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
     1621        *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
     1622        Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
     1623    }
     1624
     1625    return rc;
     1626}
     1627
     1628#ifdef IN_RING3
     1629
     1630/**
     1631 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
     1632 */
     1633PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1634{
     1635    if (cb != 1)
     1636    {
     1637        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
     1638        return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
     1639    }
     1640
     1641    ACPIState *pThis = (ACPIState *)pvUser;
     1642    DEVACPI_LOCK_R3(pThis);
     1643
     1644    *pu32 = pThis->gpe0_sts & 0xff;
     1645
     1646    DEVACPI_UNLOCK(pThis);
     1647    Log(("acpiGpe0StsRead: %#x\n", *pu32));
     1648    return VINF_SUCCESS;
     1649}
     1650
     1651/**
     1652 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
     1653 */
     1654PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1655{
     1656    if (cb != 1)
     1657        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1658
     1659    ACPIState *pThis = (ACPIState *)pvUser;
     1660    DEVACPI_LOCK_R3(pThis);
     1661
     1662    Log(("acpiGpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
     1663    u32 = pThis->gpe0_sts & ~u32;
     1664    update_gpe0(pThis, u32, pThis->gpe0_en);
     1665
     1666    DEVACPI_UNLOCK(pThis);
     1667    return VINF_SUCCESS;
     1668}
     1669
     1670/**
     1671 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
     1672 */
     1673PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     1674{
     1675    if (cb != 1)
     1676    {
     1677        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
     1678        return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
     1679    }
     1680
     1681    ACPIState *pThis = (ACPIState *)pvUser;
     1682    DEVACPI_LOCK_R3(pThis);
     1683
     1684    *pu32 = pThis->gpe0_en & 0xff;
     1685
     1686    DEVACPI_UNLOCK(pThis);
     1687    Log(("acpiGpe0EnRead: %#x\n", *pu32));
     1688    return VINF_SUCCESS;
     1689}
     1690
     1691/**
     1692 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
     1693 */
     1694PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1695{
     1696    if (cb != 1)
     1697        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1698
     1699    ACPIState *pThis = (ACPIState *)pvUser;
     1700    DEVACPI_LOCK_R3(pThis);
     1701
     1702    Log(("acpiGpe0EnWrite: %#x\n", u32));
     1703    update_gpe0(pThis, pThis->gpe0_sts, u32);
     1704
     1705    DEVACPI_UNLOCK(pThis);
     1706    return VINF_SUCCESS;
     1707}
     1708
     1709/**
     1710 * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
     1711 */
     1712PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1713{
     1714    Log(("acpiSmiWrite %#x\n", u32));
     1715    if (cb != 1)
     1716        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1717
     1718    ACPIState *pThis = (ACPIState *)pvUser;
     1719    DEVACPI_LOCK_R3(pThis);
     1720
     1721    if (u32 == ACPI_ENABLE)
     1722        pThis->pm1a_ctl |= SCI_EN;
     1723    else if (u32 == ACPI_DISABLE)
     1724        pThis->pm1a_ctl &= ~SCI_EN;
     1725    else
     1726        Log(("acpiSmiWrite: %#x <- unknown value\n", u32));
     1727
     1728    DEVACPI_UNLOCK(pThis);
     1729    return VINF_SUCCESS;
     1730}
     1731
     1732/**
     1733 * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
     1734 */
     1735PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1736{
     1737    Log(("acpiResetWrite: %#x\n", u32));
     1738    if (cb != 1)
     1739        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1740
     1741    /* No state locking required. */
     1742    int rc = VINF_SUCCESS;
     1743    if (u32 == ACPI_RESET_REG_VAL)
     1744        rc = PDMDevHlpVMReset(pDevIns);
     1745    else
     1746        Log(("acpiResetWrite: %#x <- unknown value\n", u32));
     1747
     1748    return rc;
     1749}
     1750
    7131751# ifdef DEBUG_ACPI
    714 PDMBOTHCBDECL(int) acpiDhexWrite(       PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    715 PDMBOTHCBDECL(int) acpiDchrWrite(       PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
    716 # endif
    717 #endif /* IN_RING3 */
    718 RT_C_DECLS_END
    719 
    720 
    721 #ifdef IN_RING3
    722 
    723 static RTIOPORT acpiPmPort(ACPIState* pAcpi, int32_t offset)
    724 {
    725     Assert(pAcpi->uPmIoPortBase != 0);
     1752
     1753/**
     1754 * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
     1755 */
     1756PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1757{
     1758    switch (cb)
     1759    {
     1760        case 1:
     1761            Log(("%#x\n", u32 & 0xff));
     1762            break;
     1763        case 2:
     1764            Log(("%#6x\n", u32 & 0xffff));
     1765        case 4:
     1766            Log(("%#10x\n", u32));
     1767            break;
     1768        default:
     1769            return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1770    }
     1771    return VINF_SUCCESS;
     1772}
     1773
     1774/**
     1775 * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
     1776 */
     1777PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     1778{
     1779    switch (cb)
     1780    {
     1781        case 1:
     1782            Log(("%c", u32 & 0xff));
     1783            break;
     1784        default:
     1785            return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     1786    }
     1787    return VINF_SUCCESS;
     1788}
     1789
     1790# endif /* DEBUG_ACPI */
     1791
     1792/**
     1793 * Used to calculate the value of a PM I/O port.
     1794 *
     1795 * @returns The actual I/O port value.
     1796 * @param   pThis               The ACPI instance.
     1797 * @param   offset              The offset into the I/O space, or -1 if invalid.
     1798 */
     1799static RTIOPORT acpiCalcPmPort(ACPIState *pThis, int32_t offset)
     1800{
     1801    Assert(pThis->uPmIoPortBase != 0);
    7261802
    7271803    if (offset == -1)
    7281804        return 0;
    7291805
    730     return RTIOPORT(pAcpi->uPmIoPortBase + offset);
    731 }
    732 
    733 /* Simple acpiChecksum: all the bytes must add up to 0. */
    734 static uint8_t acpiChecksum(const uint8_t * const data, size_t len)
    735 {
    736     uint8_t sum = 0;
    737     for (size_t i = 0; i < len; ++i)
    738         sum += data[i];
    739     return -sum;
    740 }
    741 
     1806    return (RTIOPORT)(pThis->uPmIoPortBase + offset);
     1807}
     1808
     1809/**
     1810 * Called by acpiLoadState and acpiUpdatePmHandlers to register the PM1a, PM
     1811 * timer and GPE0 I/O ports.
     1812 *
     1813 * @returns VBox status code.
     1814 * @param   pThis           The ACPI instance.
     1815 */
     1816static int acpiRegisterPmHandlers(ACPIState *pThis)
     1817{
     1818    int   rc = VINF_SUCCESS;
     1819
     1820#define R(offset, cnt, writer, reader, description) \
     1821    do { \
     1822        rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
     1823                                      NULL, NULL, description); \
     1824        if (RT_FAILURE(rc)) \
     1825            return rc; \
     1826    } while (0)
     1827#define L       (GPE0_BLK_LEN / 2)
     1828
     1829    R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite,       acpiPm1aEnRead,      "ACPI PM1a Enable");
     1830    R(PM1a_EVT_OFFSET,   1, acpiPM1aStsWrite,      acpiPm1aStsRead,     "ACPI PM1a Status");
     1831    R(PM1a_CTL_OFFSET,   1, acpiPM1aCtlWrite,      acpiPm1aCtlRead,     "ACPI PM1a Control");
     1832    R(PM_TMR_OFFSET,     1, NULL,                  acpiPMTmrRead,       "ACPI PM Timer");
     1833    R(GPE0_OFFSET + L,   L, acpiGpe0EnWrite,       acpiGpe0EnRead,      "ACPI GPE0 Enable");
     1834    R(GPE0_OFFSET,       L, acpiGpe0StsWrite,      acpiGpe0StsRead,     "ACPI GPE0 Status");
     1835#undef L
     1836#undef R
     1837
     1838    /* register RC stuff */
     1839    if (pThis->fGCEnabled)
     1840    {
     1841        rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
     1842                                       1, 0, NULL, "acpiPMTmrRead",
     1843                                       NULL, NULL, "ACPI PM Timer");
     1844        AssertRCReturn(rc, rc);
     1845    }
     1846
     1847    /* register R0 stuff */
     1848    if (pThis->fR0Enabled)
     1849    {
     1850        rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
     1851                                       1, 0, NULL, "acpiPMTmrRead",
     1852                                       NULL, NULL, "ACPI PM Timer");
     1853        AssertRCReturn(rc, rc);
     1854    }
     1855
     1856    return rc;
     1857}
     1858
     1859/**
     1860 * Called by acpiLoadState and acpiUpdatePmHandlers to unregister the PM1a, PM
     1861 * timer and GPE0 I/O ports.
     1862 *
     1863 * @returns VBox status code.
     1864 * @param   pThis           The ACPI instance.
     1865 */
     1866static int acpiUnregisterPmHandlers(ACPIState *pThis)
     1867{
     1868#define U(offset, cnt) \
     1869    do { \
     1870        int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt); \
     1871        AssertRCReturn(rc, rc); \
     1872    } while (0)
     1873#define L       (GPE0_BLK_LEN / 2)
     1874
     1875    U(PM1a_EVT_OFFSET+2, 1);
     1876    U(PM1a_EVT_OFFSET,   1);
     1877    U(PM1a_CTL_OFFSET,   1);
     1878    U(PM_TMR_OFFSET,     1);
     1879    U(GPE0_OFFSET + L,   L);
     1880    U(GPE0_OFFSET,       L);
     1881#undef L
     1882#undef U
     1883
     1884    return VINF_SUCCESS;
     1885}
     1886
     1887/**
     1888 * Called by acpiPciConfigWrite and acpiReset to change the location of the
     1889 * PM1a, PM timer and GPE0 ports.
     1890 *
     1891 * @returns VBox status code.
     1892 *
     1893 * @param   pThis           The ACPI instance.
     1894 * @param   NewIoPortBase   The new base address of the I/O ports.
     1895 */
     1896static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
     1897{
     1898    Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
     1899    if (NewIoPortBase != pThis->uPmIoPortBase)
     1900    {
     1901        int rc = acpiUnregisterPmHandlers(pThis);
     1902        if (RT_FAILURE(rc))
     1903            return rc;
     1904
     1905        pThis->uPmIoPortBase = NewIoPortBase;
     1906
     1907        rc = acpiRegisterPmHandlers(pThis);
     1908        if (RT_FAILURE(rc))
     1909            return rc;
     1910
     1911        /* We have to update FADT table acccording to the new base */
     1912        rc = acpiPlantTables(pThis);
     1913        AssertRC(rc);
     1914        if (RT_FAILURE(rc))
     1915            return rc;
     1916    }
     1917
     1918    return VINF_SUCCESS;
     1919}
     1920
     1921
     1922/**
     1923 * Saved state structure description, version 4.
     1924 */
     1925static const SSMFIELD g_AcpiSavedStateFields4[] =
     1926{
     1927    SSMFIELD_ENTRY(ACPIState, pm1a_en),
     1928    SSMFIELD_ENTRY(ACPIState, pm1a_sts),
     1929    SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
     1930    SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
     1931    SSMFIELD_ENTRY(ACPIState, gpe0_en),
     1932    SSMFIELD_ENTRY(ACPIState, gpe0_sts),
     1933    SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
     1934    SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
     1935    SSMFIELD_ENTRY(ACPIState, u64RamSize),
     1936    SSMFIELD_ENTRY(ACPIState, u8IndexShift),
     1937    SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
     1938    SSMFIELD_ENTRY(ACPIState, uSleepState),
     1939    SSMFIELD_ENTRY_TERM()
     1940};
     1941
     1942/**
     1943 * Saved state structure description, version 5.
     1944 */
     1945static const SSMFIELD g_AcpiSavedStateFields5[] =
     1946{
     1947    SSMFIELD_ENTRY(ACPIState, pm1a_en),
     1948    SSMFIELD_ENTRY(ACPIState, pm1a_sts),
     1949    SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
     1950    SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
     1951    SSMFIELD_ENTRY(ACPIState, gpe0_en),
     1952    SSMFIELD_ENTRY(ACPIState, gpe0_sts),
     1953    SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
     1954    SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
     1955    SSMFIELD_ENTRY(ACPIState, uSleepState),
     1956    SSMFIELD_ENTRY(ACPIState, u8IndexShift),
     1957    SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
     1958    SSMFIELD_ENTRY_TERM()
     1959};
     1960
     1961/**
     1962 * Saved state structure description, version 6.
     1963 */
     1964static const SSMFIELD g_AcpiSavedStateFields6[] =
     1965{
     1966    SSMFIELD_ENTRY(ACPIState, pm1a_en),
     1967    SSMFIELD_ENTRY(ACPIState, pm1a_sts),
     1968    SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
     1969    SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
     1970    SSMFIELD_ENTRY(ACPIState, gpe0_en),
     1971    SSMFIELD_ENTRY(ACPIState, gpe0_sts),
     1972    SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
     1973    SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
     1974    SSMFIELD_ENTRY(ACPIState, uSleepState),
     1975    SSMFIELD_ENTRY(ACPIState, u8IndexShift),
     1976    SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
     1977    SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
     1978    SSMFIELD_ENTRY_TERM()
     1979};
     1980
     1981
     1982/**
     1983 * @callback_method_impl{FNSSMDEVSAVEEXEC}
     1984 */
     1985static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
     1986{
     1987    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     1988    return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
     1989}
     1990
     1991/**
     1992 * @callback_method_impl{FNSSMDEVLOADEXEC}
     1993 */
     1994static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
     1995                                       uint32_t uVersion, uint32_t uPass)
     1996{
     1997    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     1998    Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
     1999
     2000    /*
     2001     * Unregister PM handlers, will register with actual base after state
     2002     * successfully loaded.
     2003     */
     2004    int rc = acpiUnregisterPmHandlers(pThis);
     2005    if (RT_FAILURE(rc))
     2006        return rc;
     2007
     2008    switch (uVersion)
     2009    {
     2010        case 4:
     2011            rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
     2012            break;
     2013        case 5:
     2014            rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
     2015            break;
     2016        case 6:
     2017            rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
     2018            break;
     2019        default:
     2020            rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     2021            break;
     2022    }
     2023    if (RT_SUCCESS(rc))
     2024    {
     2025        rc = acpiRegisterPmHandlers(pThis);
     2026        if (RT_FAILURE(rc))
     2027            return rc;
     2028        rc = acpiFetchBatteryStatus(pThis);
     2029        if (RT_FAILURE(rc))
     2030            return rc;
     2031        rc = acpiFetchBatteryInfo(pThis);
     2032        if (RT_FAILURE(rc))
     2033            return rc;
     2034        acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
     2035    }
     2036    return rc;
     2037}
     2038
     2039/**
     2040 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
     2041 */
     2042static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     2043{
     2044    ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
     2045    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
     2046    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
     2047    return NULL;
     2048}
     2049
     2050/**
     2051 * Calculate the check sum for some ACPI data before planting it.
     2052 *
     2053 * All the bytes must add up to 0.
     2054 *
     2055 * @returns check sum.
     2056 * @param   pvSrc       What to check sum.
     2057 * @param   cbData      The amount of data to checksum.
     2058 */
     2059static uint8_t acpiChecksum(const void * const pvSrc, size_t cbData)
     2060{
     2061    uint8_t const *pbSrc = (uint8_t const *)pvSrc;
     2062    uint8_t uSum = 0;
     2063    for (size_t i = 0; i < cbData; ++i)
     2064        uSum += pbSrc[i];
     2065    return -uSum;
     2066}
     2067
     2068/**
     2069 * Prepare a ACPI table header.
     2070 */
    7422071static void acpiPrepareHeader(ACPITBLHEADER *header, const char au8Signature[4],
    7432072                              uint32_t u32Length, uint8_t u8Revision)
     
    7542083}
    7552084
     2085/**
     2086 * Initialize a generic address structure (ACPIGENADDR).
     2087 */
    7562088static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
    7572089                                 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
     
    7652097}
    7662098
     2099/**
     2100 * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
     2101 */
    7672102static void acpiPhyscpy(ACPIState *s, RTGCPHYS32 dst, const void * const src, size_t size)
    7682103{
     
    7702105}
    7712106
    772 /** Differentiated System Description Table (DSDT) */
    773 
     2107/**
     2108 * Plant the Differentiated System Description Table (DSDT).
     2109 */
    7742110static void acpiSetupDSDT(ACPIState *s, RTGCPHYS32 addr,
    7752111                            void* pPtr, size_t uDsdtLen)
     
    7782114}
    7792115
    780 /** Secondary System Description Table (SSDT) */
    781 
     2116/**
     2117 * Plan the Secondary System Description Table (SSDT).
     2118 */
    7822119static void acpiSetupSSDT(ACPIState *s, RTGCPHYS32 addr,
    7832120                            void* pPtr, size_t uSsdtLen)
     
    7862123}
    7872124
    788 /** Firmware ACPI Control Structure (FACS) */
     2125/**
     2126 * Plant the Firmware ACPI Control Structure (FACS).
     2127 */
    7892128static void acpiSetupFACS(ACPIState *s, RTGCPHYS32 addr)
    7902129{
     
    8042143}
    8052144
    806 /** Fixed ACPI Description Table (FADT aka FACP) */
     2145/**
     2146 * Plant the Fixed ACPI Description Table (FADT aka FACP).
     2147 */
    8072148static void acpiSetupFADT(ACPIState *s, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
    8082149{
     
    8222163    fadt.u8S4BIOSReq          = 0;
    8232164    fadt.u8PStateCnt          = 0;
    824     fadt.u32PM1aEVTBLK        = RT_H2LE_U32(acpiPmPort(s, PM1a_EVT_OFFSET));
    825     fadt.u32PM1bEVTBLK        = RT_H2LE_U32(acpiPmPort(s, PM1b_EVT_OFFSET));
    826     fadt.u32PM1aCTLBLK        = RT_H2LE_U32(acpiPmPort(s, PM1a_CTL_OFFSET));
    827     fadt.u32PM1bCTLBLK        = RT_H2LE_U32(acpiPmPort(s, PM1b_CTL_OFFSET));
    828     fadt.u32PM2CTLBLK         = RT_H2LE_U32(acpiPmPort(s, PM2_CTL_OFFSET));
    829     fadt.u32PMTMRBLK          = RT_H2LE_U32(acpiPmPort(s, PM_TMR_OFFSET));
    830     fadt.u32GPE0BLK           = RT_H2LE_U32(acpiPmPort(s, GPE0_OFFSET));
    831     fadt.u32GPE1BLK           = RT_H2LE_U32(acpiPmPort(s, GPE1_OFFSET));
     2165    fadt.u32PM1aEVTBLK        = RT_H2LE_U32(acpiCalcPmPort(s, PM1a_EVT_OFFSET));
     2166    fadt.u32PM1bEVTBLK        = RT_H2LE_U32(acpiCalcPmPort(s, PM1b_EVT_OFFSET));
     2167    fadt.u32PM1aCTLBLK        = RT_H2LE_U32(acpiCalcPmPort(s, PM1a_CTL_OFFSET));
     2168    fadt.u32PM1bCTLBLK        = RT_H2LE_U32(acpiCalcPmPort(s, PM1b_CTL_OFFSET));
     2169    fadt.u32PM2CTLBLK         = RT_H2LE_U32(acpiCalcPmPort(s, PM2_CTL_OFFSET));
     2170    fadt.u32PMTMRBLK          = RT_H2LE_U32(acpiCalcPmPort(s, PM_TMR_OFFSET));
     2171    fadt.u32GPE0BLK           = RT_H2LE_U32(acpiCalcPmPort(s, GPE0_OFFSET));
     2172    fadt.u32GPE1BLK           = RT_H2LE_U32(acpiCalcPmPort(s, GPE1_OFFSET));
    8322173    fadt.u8PM1EVTLEN          = 4;
    8332174    fadt.u8PM1CTLLEN          = 2;
     
    8622203    fadt.u64XFACS             = RT_H2LE_U64((uint64_t)GCPhysFacs);
    8632204    fadt.u64XDSDT             = RT_H2LE_U64((uint64_t)GCPhysDsdt);
    864     acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiPmPort(s, PM1a_EVT_OFFSET));
    865     acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0,  0, 0, 0, acpiPmPort(s, PM1b_EVT_OFFSET));
    866     acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiPmPort(s, PM1a_CTL_OFFSET));
    867     acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0,  0, 0, 0, acpiPmPort(s, PM1b_CTL_OFFSET));
    868     acpiWriteGenericAddr(&fadt.X_PM2CTLBLK,  0,  0, 0, 0, acpiPmPort(s, PM2_CTL_OFFSET));
    869     acpiWriteGenericAddr(&fadt.X_PMTMRBLK,   1, 32, 0, 3, acpiPmPort(s, PM_TMR_OFFSET));
    870     acpiWriteGenericAddr(&fadt.X_GPE0BLK,    1, 16, 0, 1, acpiPmPort(s, GPE0_OFFSET));
    871     acpiWriteGenericAddr(&fadt.X_GPE1BLK,    0,  0, 0, 0, acpiPmPort(s, GPE1_OFFSET));
    872     fadt.header.u8Checksum    = acpiChecksum((uint8_t *)&fadt, sizeof(fadt));
     2205    acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiCalcPmPort(s, PM1a_EVT_OFFSET));
     2206    acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0,  0, 0, 0, acpiCalcPmPort(s, PM1b_EVT_OFFSET));
     2207    acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiCalcPmPort(s, PM1a_CTL_OFFSET));
     2208    acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0,  0, 0, 0, acpiCalcPmPort(s, PM1b_CTL_OFFSET));
     2209    acpiWriteGenericAddr(&fadt.X_PM2CTLBLK,  0,  0, 0, 0, acpiCalcPmPort(s, PM2_CTL_OFFSET));
     2210    acpiWriteGenericAddr(&fadt.X_PMTMRBLK,   1, 32, 0, 3, acpiCalcPmPort(s, PM_TMR_OFFSET));
     2211    acpiWriteGenericAddr(&fadt.X_GPE0BLK,    1, 16, 0, 1, acpiCalcPmPort(s, GPE0_OFFSET));
     2212    acpiWriteGenericAddr(&fadt.X_GPE1BLK,    0,  0, 0, 0, acpiCalcPmPort(s, GPE1_OFFSET));
     2213    fadt.header.u8Checksum    = acpiChecksum(&fadt, sizeof(fadt));
    8732214    acpiPhyscpy(s, GCPhysAcpi2, &fadt, sizeof(fadt));
    8742215
     
    8772218    fadt.u8IntModel           = INT_MODEL_DUAL_PIC;
    8782219    fadt.header.u8Checksum    = 0;  /* Must be zeroed before recalculating checksum! */
    879     fadt.header.u8Checksum    = acpiChecksum((uint8_t *)&fadt, ACPITBLFADT_VERSION1_SIZE);
     2220    fadt.header.u8Checksum    = acpiChecksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
    8802221    acpiPhyscpy(s, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
    8812222}
    8822223
    8832224/**
    884  * Root System Description Table.
    885  * The RSDT and XSDT tables are basically identical. The only difference is 32 vs 64 bits
    886  * addresses for description headers. RSDT is for ACPI 1.0. XSDT for ACPI 2.0 and up.
     2225 * Plant the root System Description Table.
     2226 *
     2227 * The RSDT and XSDT tables are basically identical. The only difference is 32
     2228 * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
     2229 * ACPI 2.0 and up.
    8872230 */
    8882231static int acpiSetupRSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
     
    9012244        Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
    9022245    }
    903     rsdt->header.u8Checksum = acpiChecksum((uint8_t*)rsdt, size);
     2246    rsdt->header.u8Checksum = acpiChecksum(rsdt, size);
    9042247    acpiPhyscpy(s, addr, rsdt, size);
    9052248    RTMemFree(rsdt);
     
    9072250}
    9082251
    909 /** Extended System Description Table. */
     2252/**
     2253 * Plant the Extended System Description Table.
     2254 */
    9102255static int acpiSetupXSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
    9112256{
     
    9232268        Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
    9242269    }
    925     xsdt->header.u8Checksum = acpiChecksum((uint8_t*)xsdt, size);
     2270    xsdt->header.u8Checksum = acpiChecksum(xsdt, size);
    9262271    acpiPhyscpy(s, addr, xsdt, size);
    9272272    RTMemFree(xsdt);
     
    9292274}
    9302275
    931 /** Root System Description Pointer (RSDP) */
     2276/**
     2277 * Plant the Root System Description Pointer (RSDP).
     2278 */
    9322279static void acpiSetupRSDP(ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
    9332280{
     
    9392286    rsdp->u8Revision    = ACPI_REVISION;
    9402287    rsdp->u32RSDT       = RT_H2LE_U32(GCPhysRsdt);
    941     rsdp->u8Checksum    = acpiChecksum((uint8_t*)rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
     2288    rsdp->u8Checksum    = acpiChecksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
    9422289
    9432290    /* ACPI 2.0 part (XSDT) */
    9442291    rsdp->u32Length     = RT_H2LE_U32(sizeof(ACPITBLRSDP));
    9452292    rsdp->u64XSDT       = RT_H2LE_U64(GCPhysXsdt);
    946     rsdp->u8ExtChecksum = acpiChecksum((uint8_t*)rsdp, sizeof(ACPITBLRSDP));
    947 }
    948 
    949 /**
    950  * Multiple APIC Description Table.
     2293    rsdp->u8ExtChecksum = acpiChecksum(rsdp, sizeof(ACPITBLRSDP));
     2294}
     2295
     2296/**
     2297 * Plant the Multiple APIC Description Table (MADT).
    9512298 *
    952  * @note APIC without IO-APIC hangs Windows Vista therefore we setup both
     2299 * @note    APIC without IO-APIC hangs Windows Vista therefore we setup both.
    9532300 *
    954  * @todo All hardcoded, should set this up based on the actual VM config!!!!!
     2301 * @todo    All hardcoded, should set this up based on the actual VM config!!!!!
    9552302 */
    9562303static void acpiSetupMADT(ACPIState *s, RTGCPHYS32 addr)
     
    10222369}
    10232370
    1024 
    1025 /** High Performance Event Timer (HPET) descriptor */
     2371/**
     2372 * Plant the High Performance Event Timer (HPET) descriptor.
     2373 */
    10262374static void acpiSetupHPET(ACPIState *s, RTGCPHYS32 addr)
    10272375{
     
    10442392    hpet.u8Attributes = 0;
    10452393
    1046     hpet.aHeader.u8Checksum = acpiChecksum((uint8_t *)&hpet, sizeof(hpet));
     2394    hpet.aHeader.u8Checksum = acpiChecksum(&hpet, sizeof(hpet));
    10472395
    10482396    acpiPhyscpy(s, addr, (const uint8_t *)&hpet, sizeof(hpet));
    10492397}
    10502398
    1051 /** MMCONFIG PCI config space access (MCFG) descriptor */
    1052 static void acpiSetupMCFG(ACPIState *s, RTGCPHYS32 addr)
    1053 {
    1054     struct {
     2399
     2400/**
     2401 * Used by acpiPlantTables to plant a MMCONFIG PCI config space access (MCFG)
     2402 * descriptor.
     2403 *
     2404 * @param   pThis       The ACPI instance.
     2405 * @param   GCPhysDst   Where to plant it.
     2406 */
     2407static void acpiSetupMCFG(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
     2408{
     2409    struct
     2410    {
    10552411        ACPITBLMCFG       hdr;
    10562412        ACPITBLMCFGENTRY  entry;
    1057     } tbl;
    1058 
    1059     uint8_t    u8StartBus = 0;
    1060     uint8_t    u8EndBus   = (s->u64PciConfigMMioLength >> 20) - 1;
    1061 
    1062     memset(&tbl, 0, sizeof(tbl));
     2413    }       tbl;
     2414    uint8_t u8StartBus = 0;
     2415    uint8_t u8EndBus   = (pThis->u64PciConfigMMioLength >> 20) - 1;
     2416
     2417    RT_ZERO(tbl);
    10632418
    10642419    acpiPrepareHeader(&tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
    1065     tbl.entry.u64BaseAddress = s->u64PciConfigMMioAddress;
    1066     tbl.entry.u8StartBus = u8StartBus;
    1067     tbl.entry.u8EndBus = u8EndBus;
     2420    tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
     2421    tbl.entry.u8StartBus     = u8StartBus;
     2422    tbl.entry.u8EndBus       = u8EndBus;
    10682423    // u16PciSegmentGroup must match _SEG in ACPI table
    10692424
    1070     tbl.hdr.aHeader.u8Checksum = acpiChecksum((uint8_t *)&tbl, sizeof(tbl));
    1071 
    1072     acpiPhyscpy(s, addr, (const uint8_t *)&tbl, sizeof(tbl));
    1073 }
    1074 
    1075 /* SCI IRQ */
    1076 DECLINLINE(void) acpiSetIrq(ACPIState *s, int level)
    1077 {
    1078     if (s->pm1a_ctl & SCI_EN)
    1079         PDMDevHlpPCISetIrq(s->pDevIns, -1, level);
    1080 }
    1081 
    1082 DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
    1083 {
    1084     return en & ~(RSR_EN | IGN_EN);
    1085 }
    1086 
    1087 DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
    1088 {
    1089     return sts & ~(RSR_STS | IGN_STS);
    1090 }
    1091 
    1092 DECLINLINE(int) pm1a_level(ACPIState *s)
    1093 {
    1094     return (pm1a_pure_en(s->pm1a_en) & pm1a_pure_sts(s->pm1a_sts)) != 0;
    1095 }
    1096 
    1097 DECLINLINE(int) gpe0_level(ACPIState *s)
    1098 {
    1099     return (s->gpe0_en & s->gpe0_sts) != 0;
    1100 }
    1101 
    1102 static void update_pm1a(ACPIState *s, uint32_t sts, uint32_t en)
    1103 {
    1104     int old_level, new_level;
    1105 
    1106     if (gpe0_level(s))
    1107         return;
    1108 
    1109     old_level = pm1a_level(s);
    1110     new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
    1111 
    1112     Log(("update_pm1a() old=%x new=%x\n", old_level, new_level));
    1113 
    1114     s->pm1a_en = en;
    1115     s->pm1a_sts = sts;
    1116 
    1117     if (new_level != old_level)
    1118         acpiSetIrq(s, new_level);
    1119 }
    1120 
    1121 static void update_gpe0(ACPIState *s, uint32_t sts, uint32_t en)
    1122 {
    1123     int old_level, new_level;
    1124 
    1125     if (pm1a_level(s))
    1126         return;
    1127 
    1128     old_level = (s->gpe0_en & s->gpe0_sts) != 0;
    1129     new_level = (en & sts) != 0;
    1130 
    1131     s->gpe0_en = en;
    1132     s->gpe0_sts = sts;
    1133 
    1134     if (new_level != old_level)
    1135         acpiSetIrq(s, new_level);
    1136 }
    1137 
    1138 static int acpiPowerDown(ACPIState *s)
    1139 {
    1140     int rc = PDMDevHlpVMPowerOff(s->pDevIns);
    1141     if (RT_FAILURE(rc))
    1142         AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
    1143     return rc;
    1144 }
    1145 
    1146 static int acpiSleep(ACPIState *pThis)
    1147 {
    1148     int rc;
    1149 
    1150     /* We must set WAK_STS on resume (includes restore) so the guest knows that
    1151        we've woken up and can continue executing code.  The guest is probably
    1152        reading the PMSTS register in a loop to check this. */
    1153     pThis->fSetWakeupOnResume = true;
    1154     if (pThis->fSuspendToSavedState)
    1155     {
    1156         rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
    1157         if (rc != VERR_NOT_SUPPORTED)
    1158             AssertRC(rc);
    1159         else
    1160         {
    1161             LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
    1162             rc = PDMDevHlpVMSuspend(pThis->pDevIns);
    1163             AssertRC(rc);
    1164         }
    1165     }
    1166     else
    1167     {
    1168         rc = PDMDevHlpVMSuspend(pThis->pDevIns);
    1169         AssertRC(rc);
    1170     }
    1171     return rc;
    1172 }
    1173 
    1174 /** Converts a ACPI port interface pointer to an ACPI state pointer. */
    1175 #define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
    1176 
    1177 /**
    1178  * Send an ACPI power off event.
     2425    tbl.hdr.aHeader.u8Checksum = acpiChecksum(&tbl, sizeof(tbl));
     2426
     2427    acpiPhyscpy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
     2428}
     2429
     2430/**
     2431 * Used by acpiPlantTables and acpiConstruct.
    11792432 *
    1180  * @returns VBox status code
    1181  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1182  */
    1183 static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
    1184 {
    1185     ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
    1186     Log(("acpiPowerButtonPress: handled=%d status=%x\n", s->fPowerButtonHandled, s->pm1a_sts));
    1187     s->fPowerButtonHandled = false;
    1188     update_pm1a(s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
    1189     return VINF_SUCCESS;
    1190 }
    1191 
    1192 /**
    1193  * Check if the ACPI power button event was handled.
    1194  *
    1195  * @returns VBox status code
    1196  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1197  * @param   pfHandled       Return true if the power button event was handled by the guest.
    1198  */
    1199 static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
    1200 {
    1201     ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
    1202     *pfHandled = s->fPowerButtonHandled;
    1203     return VINF_SUCCESS;
    1204 }
    1205 
    1206 /**
    1207  * Check if the Guest entered into G0 (working) or G1 (sleeping).
    1208  *
    1209  * @returns VBox status code
    1210  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1211  * @param   pfEntered       Return true if the guest entered the ACPI mode.
    1212  */
    1213 static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
    1214 {
    1215     ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
    1216     *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
    1217     return VINF_SUCCESS;
    1218 }
    1219 
    1220 static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
    1221 {
    1222     ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
    1223     *pfLocked = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, uCpu);
    1224     return VINF_SUCCESS;
    1225 }
    1226 
    1227 /**
    1228  * Send an ACPI sleep button event.
    1229  *
    1230  * @returns VBox status code
    1231  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    1232  */
    1233 static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
    1234 {
    1235     ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
    1236     update_pm1a(s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
    1237     return VINF_SUCCESS;
    1238 }
    1239 
    1240 /* PM1a_EVT_BLK enable */
    1241 static uint32_t acpiPm1aEnReadw(ACPIState *s, uint32_t addr)
    1242 {
    1243     uint16_t val = s->pm1a_en;
    1244     Log(("acpi: acpiPm1aEnReadw -> %#x\n", val));
    1245     return val;
    1246 }
    1247 
    1248 static void acpiPM1aEnWritew(ACPIState *s, uint32_t addr, uint32_t val)
    1249 {
    1250     Log(("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
    1251     val &= ~(RSR_EN | IGN_EN);
    1252     update_pm1a(s, s->pm1a_sts, val);
    1253 }
    1254 
    1255 /* PM1a_EVT_BLK status */
    1256 static uint32_t acpiPm1aStsReadw(ACPIState *s, uint32_t addr)
    1257 {
    1258     uint16_t val = s->pm1a_sts;
    1259     Log(("acpi: acpiPm1aStsReadw -> %#x\n", val));
    1260     return val;
    1261 }
    1262 
    1263 static void acpiPM1aStsWritew(ACPIState *s, uint32_t addr, uint32_t val)
    1264 {
    1265     Log(("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
    1266     if (val & PWRBTN_STS)
    1267         s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
    1268     val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
    1269     update_pm1a(s, val, s->pm1a_en);
    1270 }
    1271 
    1272 /* PM1a_CTL_BLK */
    1273 static uint32_t acpiPm1aCtlReadw(ACPIState *s, uint32_t addr)
    1274 {
    1275     uint16_t val = s->pm1a_ctl;
    1276     Log(("acpi: acpiPm1aCtlReadw -> %#x\n", val));
    1277     return val;
    1278 }
    1279 
    1280 static int acpiPM1aCtlWritew(ACPIState *s, uint32_t addr, uint32_t val)
    1281 {
    1282     uint32_t uSleepState;
    1283 
    1284     Log(("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
    1285     s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
    1286 
    1287     uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
    1288     if (uSleepState != s->uSleepState)
    1289     {
    1290         s->uSleepState = uSleepState;
    1291         switch (uSleepState)
    1292         {
    1293             case 0x00:                  /* S0 */
    1294                 break;
    1295             case 0x01:                  /* S1 */
    1296                 if (s->fS1Enabled)
    1297                 {
    1298                     LogRel(("Entering S1 power state (powered-on suspend)\n"));
    1299                     return acpiSleep(s);
    1300                 }
    1301                 else
    1302                     LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
    1303             case 0x04:                  /* S4 */
    1304                 if (s->fS4Enabled)
    1305                 {
    1306                     LogRel(("Entering S4 power state (suspend to disk)\n"));
    1307                     return acpiPowerDown(s);/* Same behavior as S5 */
    1308                 }
    1309                 else
    1310                     LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
    1311             case 0x05:                  /* S5 */
    1312                 LogRel(("Entering S5 power state (power down)\n"));
    1313                 return acpiPowerDown(s);
    1314             default:
    1315                 AssertMsgFailed(("Unknown sleep state %#x\n", uSleepState));
    1316                 break;
    1317         }
    1318     }
    1319     return VINF_SUCCESS;
    1320 }
    1321 
    1322 /* GPE0_BLK */
    1323 static uint32_t acpiGpe0EnReadb(ACPIState *s, uint32_t addr)
    1324 {
    1325     uint8_t val = s->gpe0_en;
    1326     Log(("acpi: acpiGpe0EnReadl -> %#x\n", val));
    1327     return val;
    1328 }
    1329 
    1330 static void acpiGpe0EnWriteb(ACPIState *s, uint32_t addr, uint32_t val)
    1331 {
    1332     Log(("acpi: acpiGpe0EnWritel <- %#x\n", val));
    1333     update_gpe0(s, s->gpe0_sts, val);
    1334 }
    1335 
    1336 static uint32_t acpiGpe0StsReadb(ACPIState *s, uint32_t addr)
    1337 {
    1338     uint8_t val = s->gpe0_sts;
    1339     Log(("acpi: acpiGpe0StsReadl -> %#x\n", val));
    1340     return val;
    1341 }
    1342 
    1343 static void acpiGpe0StsWriteb(ACPIState *s, uint32_t addr, uint32_t val)
    1344 {
    1345     val = s->gpe0_sts & ~val;
    1346     update_gpe0(s, val, s->gpe0_en);
    1347     Log(("acpi: acpiGpe0StsWritel <- %#x\n", val));
    1348 }
    1349 
    1350 static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
    1351 {
    1352     int rc = VINF_SUCCESS;
    1353 
    1354     Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
    1355     if (val == ACPI_RESET_REG_VAL)
    1356     {
    1357 # ifndef IN_RING3
    1358         rc = VINF_IOM_HC_IOPORT_WRITE;
    1359 # else /* IN_RING3 */
    1360         rc = PDMDevHlpVMReset(s->pDevIns);
    1361 # endif /* !IN_RING3 */
    1362     }
    1363     return rc;
    1364 }
    1365 
    1366 /* SMI */
    1367 static void acpiSmiWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
    1368 {
    1369     Log(("acpi: acpiSmiWriteU8 %#x\n", val));
    1370     if (val == ACPI_ENABLE)
    1371         s->pm1a_ctl |= SCI_EN;
    1372     else if (val == ACPI_DISABLE)
    1373         s->pm1a_ctl &= ~SCI_EN;
    1374     else
    1375         Log(("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
    1376 }
    1377 
     2433 * @returns Guest memory address.
     2434 */
    13782435static uint32_t find_rsdp_space(void)
    13792436{
     
    13812438}
    13822439
    1383 static int acpiPMTimerReset(ACPIState *s)
    1384 {
    1385     uint64_t interval, freq;
    1386 
    1387     freq = TMTimerGetFreq(s->CTX_SUFF(ts));
    1388     interval = ASMMultU64ByU32DivByU32(0xffffffff, freq, PM_TMR_FREQ);
    1389     Log(("interval = %RU64\n", interval));
    1390     TMTimerSet(s->CTX_SUFF(ts), TMTimerGet(s->CTX_SUFF(ts)) + interval);
    1391 
    1392     return VINF_SUCCESS;
    1393 }
    1394 
    1395 static DECLCALLBACK(void) acpiTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1396 {
    1397     ACPIState *s = (ACPIState *)pvUser;
    1398 
    1399     Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
    1400          s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
    1401          s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
    1402 
    1403     update_pm1a(s, s->pm1a_sts | TMR_STS, s->pm1a_en);
    1404     acpiPMTimerReset(s);
    1405 }
    1406 
    1407 /**
    1408  * _BST method.
    1409  */
    1410 static int acpiFetchBatteryStatus(ACPIState *s)
    1411 {
    1412     uint32_t           *p = s->au8BatteryInfo;
    1413     bool               fPresent;              /* battery present? */
    1414     PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
    1415     PDMACPIBATSTATE    hostBatteryState;      /* bitfield */
    1416     uint32_t           hostPresentRate;       /* 0..1000 */
    1417     int                rc;
    1418 
    1419     if (!s->pDrv)
    1420         return VINF_SUCCESS;
    1421     rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
    1422                                         &hostBatteryState, &hostPresentRate);
    1423     AssertRC(rc);
    1424 
    1425     /* default values */
    1426     p[BAT_STATUS_STATE]              = hostBatteryState;
    1427     p[BAT_STATUS_PRESENT_RATE]       = hostPresentRate == ~0U ? 0xFFFFFFFF
    1428                                                               : hostPresentRate * 50;  /* mW */
    1429     p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
    1430     p[BAT_STATUS_PRESENT_VOLTAGE]    = 10000; /* mV */
    1431 
    1432     /* did we get a valid battery state? */
    1433     if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
    1434         p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
    1435     if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
    1436         p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
    1437 
    1438     return VINF_SUCCESS;
    1439 }
    1440 
    1441 /**
    1442  * _BIF method.
    1443  */
    1444 static int acpiFetchBatteryInfo(ACPIState *s)
    1445 {
    1446     uint32_t *p = s->au8BatteryInfo;
    1447 
    1448     p[BAT_INFO_UNITS]                      = 0;     /* mWh */
    1449     p[BAT_INFO_DESIGN_CAPACITY]            = 50000; /* mWh */
    1450     p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY]  = 50000; /* mWh */
    1451     p[BAT_INFO_TECHNOLOGY]                 = BAT_TECH_PRIMARY;
    1452     p[BAT_INFO_DESIGN_VOLTAGE]             = 10000; /* mV */
    1453     p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100;   /* mWh */
    1454     p[BAT_INFO_DESIGN_CAPACITY_OF_LOW]     = 50;    /* mWh */
    1455     p[BAT_INFO_CAPACITY_GRANULARITY_1]     = 1;     /* mWh */
    1456     p[BAT_INFO_CAPACITY_GRANULARITY_2]     = 1;     /* mWh */
    1457 
    1458     return VINF_SUCCESS;
    1459 }
    1460 
    1461 /**
    1462  * _STA method.
    1463  */
    1464 static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
    1465 {
    1466     bool               fPresent;              /* battery present? */
    1467     PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
    1468     PDMACPIBATSTATE    hostBatteryState;      /* bitfield */
    1469     uint32_t           hostPresentRate;       /* 0..1000 */
    1470     int                rc;
    1471 
    1472     if (!s->pDrv)
    1473         return 0;
    1474     rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
    1475                                         &hostBatteryState, &hostPresentRate);
    1476     AssertRC(rc);
    1477 
    1478     return fPresent
    1479         ?   STA_DEVICE_PRESENT_MASK                     /* present */
    1480           | STA_DEVICE_ENABLED_MASK                     /* enabled and decodes its resources */
    1481           | STA_DEVICE_SHOW_IN_UI_MASK                  /* should be shown in UI */
    1482           | STA_DEVICE_FUNCTIONING_PROPERLY_MASK        /* functioning properly */
    1483           | STA_BATTERY_PRESENT_MASK                    /* battery is present */
    1484         : 0;                                            /* device not present */
    1485 }
    1486 
    1487 static uint32_t acpiGetPowerSource(ACPIState *s)
    1488 {
    1489     PDMACPIPOWERSOURCE ps;
    1490 
    1491     /* query the current power source from the host driver */
    1492     if (!s->pDrv)
    1493         return AC_ONLINE;
    1494     int rc = s->pDrv->pfnQueryPowerSource(s->pDrv, &ps);
    1495     AssertRC(rc);
    1496     return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
    1497 }
    1498 
    1499 PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1500 {
    1501     ACPIState *s = (ACPIState *)pvUser;
    1502 
    1503     switch (cb)
    1504     {
    1505         case 4:
    1506             u32 >>= s->u8IndexShift;
    1507             /* see comment at the declaration of u8IndexShift */
    1508             if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
    1509             {
    1510                 s->u8IndexShift = 2;
    1511                 u32 >>= 2;
    1512             }
    1513             Assert(u32 < BAT_INDEX_LAST);
    1514             s->uBatteryIndex = u32;
    1515             break;
    1516         default:
    1517             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1518             break;
    1519     }
    1520     return VINF_SUCCESS;
    1521 }
    1522 
    1523 PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1524 {
    1525     ACPIState *s = (ACPIState *)pvUser;
    1526 
    1527     switch (cb)
    1528     {
    1529         case 4:
    1530             switch (s->uBatteryIndex)
    1531             {
    1532                 case BAT_STATUS_STATE:
    1533                     acpiFetchBatteryStatus(s);
    1534                 case BAT_STATUS_PRESENT_RATE:
    1535                 case BAT_STATUS_REMAINING_CAPACITY:
    1536                 case BAT_STATUS_PRESENT_VOLTAGE:
    1537                     *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
    1538                     break;
    1539 
    1540                 case BAT_INFO_UNITS:
    1541                     acpiFetchBatteryInfo(s);
    1542                 case BAT_INFO_DESIGN_CAPACITY:
    1543                 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
    1544                 case BAT_INFO_TECHNOLOGY:
    1545                 case BAT_INFO_DESIGN_VOLTAGE:
    1546                 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
    1547                 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
    1548                 case BAT_INFO_CAPACITY_GRANULARITY_1:
    1549                 case BAT_INFO_CAPACITY_GRANULARITY_2:
    1550                     *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
    1551                     break;
    1552 
    1553                 case BAT_DEVICE_STATUS:
    1554                     *pu32 = acpiGetBatteryDeviceStatus(s);
    1555                     break;
    1556 
    1557                 case BAT_POWER_SOURCE:
    1558                     *pu32 = acpiGetPowerSource(s);
    1559                     break;
    1560 
    1561                 default:
    1562                     AssertMsgFailed(("Invalid battery index %d\n", s->uBatteryIndex));
    1563                     break;
    1564             }
    1565             break;
    1566         default:
    1567             return VERR_IOM_IOPORT_UNUSED;
    1568     }
    1569     return VINF_SUCCESS;
    1570 }
    1571 
    1572 PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1573 {
    1574     ACPIState *s = (ACPIState *)pvUser;
    1575 
    1576     Log(("system_index = %d, %d\n", u32, u32 >> 2));
    1577     switch (cb)
    1578     {
    1579         case 4:
    1580             if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
    1581                 s->uSystemInfoIndex = u32;
    1582             else
    1583             {
    1584                 /* see comment at the declaration of u8IndexShift */
    1585                 if ((u32 > SYSTEM_INFO_INDEX_END) && (s->u8IndexShift == 0))
    1586                 {
    1587                     if (((u32 >> 2) < SYSTEM_INFO_INDEX_END) && ((u32 & 0x3)) == 0)
    1588                     {
    1589                         s->u8IndexShift = 2;
    1590                     }
    1591                 }
    1592 
    1593                 u32 >>= s->u8IndexShift;
    1594                 Assert(u32 < SYSTEM_INFO_INDEX_END);
    1595                 s->uSystemInfoIndex = u32;
    1596             }
    1597             break;
    1598 
    1599         default:
    1600             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1601             break;
    1602     }
    1603     return VINF_SUCCESS;
    1604 }
    1605 
    1606 PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1607 {
    1608     ACPIState *s = (ACPIState *)pvUser;
    1609 
    1610     switch (cb)
    1611     {
    1612         case 4:
    1613             switch (s->uSystemInfoIndex)
    1614             {
    1615                 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
    1616                     *pu32 = s->cbRamLow;
    1617                     break;
    1618 
    1619                 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
    1620                     *pu32 = s->cbRamHigh >> 16; /* 64KB units */
    1621                     Assert(((uint64_t)*pu32 << 16) == s->cbRamHigh);
    1622                     break;
    1623 
    1624                 case SYSTEM_INFO_INDEX_USE_IOAPIC:
    1625                     *pu32 = s->u8UseIOApic;
    1626                     break;
    1627 
    1628                 case SYSTEM_INFO_INDEX_HPET_STATUS:
    1629                     *pu32 = s->fUseHpet ? (  STA_DEVICE_PRESENT_MASK
    1630                                            | STA_DEVICE_ENABLED_MASK
    1631                                            | STA_DEVICE_SHOW_IN_UI_MASK
    1632                                            | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
    1633                                         : 0;
    1634                     break;
    1635 
    1636                 case SYSTEM_INFO_INDEX_SMC_STATUS:
    1637                     *pu32 = s->fUseSmc ? (  STA_DEVICE_PRESENT_MASK
    1638                                           | STA_DEVICE_ENABLED_MASK
    1639                                           /* no need to show this device in the UI */
    1640                                           | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
    1641                                        : 0;
    1642                     break;
    1643 
    1644                 case SYSTEM_INFO_INDEX_FDC_STATUS:
    1645                     *pu32 = s->fUseFdc ? (  STA_DEVICE_PRESENT_MASK
    1646                                           | STA_DEVICE_ENABLED_MASK
    1647                                           | STA_DEVICE_SHOW_IN_UI_MASK
    1648                                           | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
    1649                                        : 0;
    1650                     break;
    1651 
    1652                 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
    1653                     *pu32 = s->u32NicPciAddress;
    1654                     break;
    1655 
    1656                 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
    1657                     *pu32 = s->u32AudioPciAddress;
    1658                     break;
    1659 
    1660                 case SYSTEM_INFO_INDEX_POWER_STATES:
    1661                     *pu32 = RT_BIT(0) | RT_BIT(5);  /* S1 and S5 always exposed */
    1662                     if (s->fS1Enabled)              /* Optionally expose S1 and S4 */
    1663                         *pu32 |= RT_BIT(1);
    1664                     if (s->fS4Enabled)
    1665                         *pu32 |= RT_BIT(4);
    1666                     break;
    1667 
    1668                case SYSTEM_INFO_INDEX_IOC_ADDRESS:
    1669                     *pu32 = s->u32IocPciAddress;
    1670                     break;
    1671 
    1672                 case SYSTEM_INFO_INDEX_HBC_ADDRESS:
    1673                     *pu32 = s->u32HbcPciAddress;
    1674                     break;
    1675 
    1676                 case SYSTEM_INFO_INDEX_PCI_BASE:
    1677                     /** @todo: couldn't MCFG be in 64-bit range? */
    1678                     Assert(s->u64PciConfigMMioAddress < 0xffffffff);
    1679                     *pu32 = (uint32_t)s->u64PciConfigMMioAddress;
    1680                     break;
    1681 
    1682                 case SYSTEM_INFO_INDEX_PCI_LENGTH:
    1683                     /** @todo: couldn't MCFG be in 64-bit range? */
    1684                     Assert(s->u64PciConfigMMioLength< 0xffffffff);
    1685                     *pu32 = (uint32_t)s->u64PciConfigMMioLength;
    1686                     break;
    1687 
    1688                 /* This is only for compatibility with older saved states that
    1689                    may include ACPI code that read these values.  Legacy is
    1690                    a wonderful thing, isn't it? :-) */
    1691                 case SYSTEM_INFO_INDEX_CPU0_STATUS:
    1692                 case SYSTEM_INFO_INDEX_CPU1_STATUS:
    1693                 case SYSTEM_INFO_INDEX_CPU2_STATUS:
    1694                 case SYSTEM_INFO_INDEX_CPU3_STATUS:
    1695                     *pu32 = (   s->fShowCpu
    1696                              && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
    1697                              && VMCPUSET_IS_PRESENT(&s->CpuSetAttached,
    1698                                                     s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS))
    1699                                         ? (  STA_DEVICE_PRESENT_MASK
    1700                                            | STA_DEVICE_ENABLED_MASK
    1701                                            | STA_DEVICE_SHOW_IN_UI_MASK
    1702                                            | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
    1703                                         : 0;
    1704                     break;
    1705 
    1706                 case SYSTEM_INFO_INDEX_RTC_STATUS:
    1707                     *pu32 = s->fShowRtc ? (  STA_DEVICE_PRESENT_MASK
    1708                                            | STA_DEVICE_ENABLED_MASK
    1709                                            | STA_DEVICE_SHOW_IN_UI_MASK
    1710                                            | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
    1711                                         : 0;
    1712                     break;
    1713 
    1714                 case SYSTEM_INFO_INDEX_CPU_LOCKED:
    1715                 {
    1716                     if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
    1717                     {
    1718                         *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
    1719                         s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
    1720                     }
    1721                     else
    1722                     {
    1723                         AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
    1724                         /* Always return locked status just to be safe */
    1725                         *pu32 = 1;
    1726                     }
    1727                     break;
    1728                 }
    1729 
    1730                 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
    1731                     *pu32 = s->u32CpuEventType;
    1732                     break;
    1733 
    1734                 case SYSTEM_INFO_INDEX_CPU_EVENT:
    1735                     *pu32 = s->u32CpuEvent;
    1736                     break;
    1737 
    1738                 case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
    1739                     *pu32 = s->uSerial0IoPortBase;
    1740                     break;
    1741 
    1742                 case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
    1743                     *pu32 = s->uSerial0Irq;
    1744                     break;
    1745 
    1746                 case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
    1747                     *pu32 = s->uSerial1IoPortBase;
    1748                     break;
    1749 
    1750                 case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
    1751                     *pu32 = s->uSerial1Irq;
    1752                     break;
    1753 
    1754                 case SYSTEM_INFO_INDEX_END:
    1755                     break;
    1756 
    1757                 /* Solaris 9 tries to read from this index */
    1758                 case SYSTEM_INFO_INDEX_INVALID:
    1759                     *pu32 = 0;
    1760                     break;
    1761 
    1762                 default:
    1763                     AssertMsgFailed(("Invalid system info index %d\n", s->uSystemInfoIndex));
    1764                     break;
    1765             }
    1766             break;
    1767 
    1768         default:
    1769             return VERR_IOM_IOPORT_UNUSED;
    1770     }
    1771 
    1772     Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
    1773     return VINF_SUCCESS;
    1774 }
    1775 
    1776 PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1777 {
    1778     ACPIState *s = (ACPIState *)pvUser;
    1779 
    1780     Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
    1781 
    1782     if (cb == 4)
    1783     {
    1784         switch (s->uSystemInfoIndex)
    1785         {
    1786             case SYSTEM_INFO_INDEX_INVALID:
    1787                 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
    1788                 s->u8IndexShift = 0;
    1789                 break;
    1790 
    1791             case SYSTEM_INFO_INDEX_VALID:
    1792                 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
    1793                 s->u8IndexShift = 2;
    1794                 break;
    1795 
    1796             case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
    1797                 s->idCpuLockCheck = u32;
    1798                 break;
    1799 
    1800             case SYSTEM_INFO_INDEX_CPU_LOCKED:
    1801                 if (u32 < s->cCpus)
    1802                     VMCPUSET_DEL(&s->CpuSetLocked, u32); /* Unlock the CPU */
    1803                 else
    1804                     LogRel(("ACPI: CPU %u does not exist\n", u32));
    1805                 break;
    1806 
    1807             default:
    1808                 AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
    1809                                 Port, cb, u32, s->uSystemInfoIndex));
    1810                 break;
    1811         }
    1812     }
    1813     else
    1814         AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1815     return VINF_SUCCESS;
    1816 }
    1817 
    1818 /** @todo Don't call functions, but do the job in the read/write handlers
    1819  *        here! */
    1820 
    1821 /* IO Helpers */
    1822 PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1823 {
    1824     switch (cb)
    1825     {
    1826         case 2:
    1827             *pu32 = acpiPm1aEnReadw((ACPIState*)pvUser, Port);
    1828             break;
    1829         default:
    1830             return VERR_IOM_IOPORT_UNUSED;
    1831     }
    1832     return VINF_SUCCESS;
    1833 }
    1834 
    1835 PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1836 {
    1837     switch (cb)
    1838     {
    1839         case 2:
    1840             *pu32 = acpiPm1aStsReadw((ACPIState*)pvUser, Port);
    1841             break;
    1842         default:
    1843             AssertMsgFailed(("PM1 status read: width %d\n", cb));
    1844             return VERR_IOM_IOPORT_UNUSED;
    1845     }
    1846     return VINF_SUCCESS;
    1847 }
    1848 
    1849 PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1850 {
    1851     switch (cb)
    1852     {
    1853         case 2:
    1854             *pu32 = acpiPm1aCtlReadw((ACPIState*)pvUser, Port);
    1855             break;
    1856         default:
    1857             AssertMsgFailed(("PM1 control read: width %d\n", cb));
    1858             return VERR_IOM_IOPORT_UNUSED;
    1859     }
    1860     return VINF_SUCCESS;
    1861 }
    1862 
    1863 PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1864 {
    1865     switch (cb)
    1866     {
    1867         case 2:
    1868             acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32);
    1869             break;
    1870         case 4:
    1871             acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
    1872             break;
    1873         default:
    1874             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1875             break;
    1876     }
    1877     return VINF_SUCCESS;
    1878 }
    1879 
    1880 PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1881 {
    1882     switch (cb)
    1883     {
    1884         case 2:
    1885             acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32);
    1886             break;
    1887         case 4:
    1888             acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
    1889             break;
    1890         default:
    1891             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1892             break;
    1893     }
    1894     return VINF_SUCCESS;
    1895 }
    1896 
    1897 PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1898 {
    1899     switch (cb)
    1900     {
    1901         case 2:
    1902             return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32);
    1903         case 4:
    1904             return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
    1905         default:
    1906             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1907             break;
    1908     }
    1909     return VINF_SUCCESS;
    1910 }
    1911 
    1912 #endif /* IN_RING3 */
    1913 
    1914 /**
    1915  * PMTMR readable from host/guest.
    1916  */
    1917 PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1918 {
    1919     if (cb == 4)
    1920     {
    1921         ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
    1922         uint64_t u64Now = TMTimerGet(s->CTX_SUFF(ts));
    1923         uint64_t u64Seen;
    1924         do
    1925         {
    1926             u64Seen = ASMAtomicReadU64(&s->u64PmTimerLastSeen);
    1927             if (u64Now < u64Seen)
    1928                 u64Now = u64Seen + 1;
    1929         } while (!ASMAtomicCmpXchgU64(&s->u64PmTimerLastSeen, u64Now, u64Seen));
    1930 
    1931         uint64_t u64Elapsed = u64Now - s->u64PmTimerInitial;
    1932         *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(s->CTX_SUFF(ts)));
    1933         Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
    1934         return VINF_SUCCESS;
    1935     }
    1936     return VERR_IOM_IOPORT_UNUSED;
    1937 }
    1938 
    1939 #ifdef IN_RING3
    1940 
    1941 PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1942 {
    1943     switch (cb)
    1944     {
    1945         case 1:
    1946             *pu32 = acpiGpe0StsReadb((ACPIState*)pvUser, Port);
    1947             break;
    1948         default:
    1949             return VERR_IOM_IOPORT_UNUSED;
    1950     }
    1951     return VINF_SUCCESS;
    1952 }
    1953 
    1954 PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
    1955 {
    1956     switch (cb)
    1957     {
    1958         case 1:
    1959             *pu32 = acpiGpe0EnReadb((ACPIState*)pvUser, Port);
    1960             break;
    1961         default:
    1962             return VERR_IOM_IOPORT_UNUSED;
    1963     }
    1964     return VINF_SUCCESS;
    1965 }
    1966 
    1967 PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1968 {
    1969     switch (cb)
    1970     {
    1971         case 1:
    1972             acpiGpe0StsWriteb((ACPIState*)pvUser, Port, u32);
    1973             break;
    1974         default:
    1975             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1976             break;
    1977     }
    1978     return VINF_SUCCESS;
    1979 }
    1980 
    1981 PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1982 {
    1983     switch (cb)
    1984     {
    1985         case 1:
    1986             acpiGpe0EnWriteb((ACPIState*)pvUser, Port, u32);
    1987             break;
    1988         default:
    1989             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    1990             break;
    1991     }
    1992     return VINF_SUCCESS;
    1993 }
    1994 
    1995 PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    1996 {
    1997     switch (cb)
    1998     {
    1999         case 1:
    2000             acpiSmiWriteU8((ACPIState*)pvUser, Port, u32);
    2001             break;
    2002         default:
    2003             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    2004             break;
    2005     }
    2006     return VINF_SUCCESS;
    2007 }
    2008 
    2009 PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    2010 {
    2011     switch (cb)
    2012     {
    2013         case 1:
    2014             return acpiResetWriteU8((ACPIState*)pvUser, Port, u32);
    2015         default:
    2016             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    2017             break;
    2018     }
    2019     return VINF_SUCCESS;
    2020 }
    2021 
    2022 #ifdef DEBUG_ACPI
    2023 
    2024 PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    2025 {
    2026     switch (cb)
    2027     {
    2028         case 1:
    2029             Log(("%#x\n", u32 & 0xff));
    2030             break;
    2031         case 2:
    2032             Log(("%#6x\n", u32 & 0xffff));
    2033         case 4:
    2034             Log(("%#10x\n", u32));
    2035             break;
    2036         default:
    2037             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    2038             break;
    2039     }
    2040     return VINF_SUCCESS;
    2041 }
    2042 
    2043 PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
    2044 {
    2045     switch (cb)
    2046     {
    2047         case 1:
    2048             Log(("%c", u32 & 0xff));
    2049             break;
    2050         default:
    2051             AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
    2052             break;
    2053     }
    2054     return VINF_SUCCESS;
    2055 }
    2056 
    2057 #endif /* DEBUG_ACPI */
    2058 
    2059 static int acpiRegisterPmHandlers(ACPIState*  pThis)
    2060 {
    2061     int   rc = VINF_SUCCESS;
    2062 
    2063 #define R(offset, cnt, writer, reader, description) \
    2064     do { \
    2065         rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt, pThis, writer, reader, \
    2066                                       NULL, NULL, description); \
    2067         if (RT_FAILURE(rc)) \
    2068             return rc; \
    2069     } while (0)
    2070 #define L       (GPE0_BLK_LEN / 2)
    2071 
    2072     R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite,       acpiPm1aEnRead,      "ACPI PM1a Enable");
    2073     R(PM1a_EVT_OFFSET,   1, acpiPM1aStsWrite,      acpiPm1aStsRead,     "ACPI PM1a Status");
    2074     R(PM1a_CTL_OFFSET,   1, acpiPM1aCtlWrite,      acpiPm1aCtlRead,     "ACPI PM1a Control");
    2075     R(PM_TMR_OFFSET,     1, NULL,                  acpiPMTmrRead,       "ACPI PM Timer");
    2076     R(GPE0_OFFSET + L,   L, acpiGpe0EnWrite,       acpiGpe0EnRead,      "ACPI GPE0 Enable");
    2077     R(GPE0_OFFSET,       L, acpiGpe0StsWrite,      acpiGpe0StsRead,     "ACPI GPE0 Status");
    2078 #undef L
    2079 #undef R
    2080 
    2081     /* register RC stuff */
    2082     if (pThis->fGCEnabled)
    2083     {
    2084         rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
    2085                                        1, 0, NULL, "acpiPMTmrRead",
    2086                                        NULL, NULL, "ACPI PM Timer");
    2087         AssertRCReturn(rc, rc);
    2088     }
    2089 
    2090     /* register R0 stuff */
    2091     if (pThis->fR0Enabled)
    2092     {
    2093         rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
    2094                                        1, 0, NULL, "acpiPMTmrRead",
    2095                                        NULL, NULL, "ACPI PM Timer");
    2096         AssertRCReturn(rc, rc);
    2097     }
    2098 
    2099     return rc;
    2100 }
    2101 
    2102 static int acpiUnregisterPmHandlers(ACPIState *pThis)
    2103 {
    2104 #define U(offset, cnt) \
    2105     do { \
    2106         int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt); \
    2107         AssertRCReturn(rc, rc); \
    2108     } while (0)
    2109 #define L       (GPE0_BLK_LEN / 2)
    2110 
    2111     U(PM1a_EVT_OFFSET+2, 1);
    2112     U(PM1a_EVT_OFFSET,   1);
    2113     U(PM1a_CTL_OFFSET,   1);
    2114     U(PM_TMR_OFFSET,     1);
    2115     U(GPE0_OFFSET + L,   L);
    2116     U(GPE0_OFFSET,       L);
    2117 #undef L
    2118 #undef U
    2119 
    2120     return VINF_SUCCESS;
    2121 }
    2122 
    2123 /**
    2124  * Saved state structure description, version 4.
    2125  */
    2126 static const SSMFIELD g_AcpiSavedStateFields4[] =
    2127 {
    2128     SSMFIELD_ENTRY(ACPIState, pm1a_en),
    2129     SSMFIELD_ENTRY(ACPIState, pm1a_sts),
    2130     SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
    2131     SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
    2132     SSMFIELD_ENTRY(ACPIState, gpe0_en),
    2133     SSMFIELD_ENTRY(ACPIState, gpe0_sts),
    2134     SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
    2135     SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
    2136     SSMFIELD_ENTRY(ACPIState, u64RamSize),
    2137     SSMFIELD_ENTRY(ACPIState, u8IndexShift),
    2138     SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
    2139     SSMFIELD_ENTRY(ACPIState, uSleepState),
    2140     SSMFIELD_ENTRY_TERM()
    2141 };
    2142 
    2143 /**
    2144  * Saved state structure description, version 5.
    2145  */
    2146 static const SSMFIELD g_AcpiSavedStateFields5[] =
    2147 {
    2148     SSMFIELD_ENTRY(ACPIState, pm1a_en),
    2149     SSMFIELD_ENTRY(ACPIState, pm1a_sts),
    2150     SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
    2151     SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
    2152     SSMFIELD_ENTRY(ACPIState, gpe0_en),
    2153     SSMFIELD_ENTRY(ACPIState, gpe0_sts),
    2154     SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
    2155     SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
    2156     SSMFIELD_ENTRY(ACPIState, uSleepState),
    2157     SSMFIELD_ENTRY(ACPIState, u8IndexShift),
    2158     SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
    2159     SSMFIELD_ENTRY_TERM()
    2160 };
    2161 
    2162 /**
    2163  * Saved state structure description, version 6.
    2164  */
    2165 static const SSMFIELD g_AcpiSavedStateFields6[] =
    2166 {
    2167     SSMFIELD_ENTRY(ACPIState, pm1a_en),
    2168     SSMFIELD_ENTRY(ACPIState, pm1a_sts),
    2169     SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
    2170     SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
    2171     SSMFIELD_ENTRY(ACPIState, gpe0_en),
    2172     SSMFIELD_ENTRY(ACPIState, gpe0_sts),
    2173     SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
    2174     SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
    2175     SSMFIELD_ENTRY(ACPIState, uSleepState),
    2176     SSMFIELD_ENTRY(ACPIState, u8IndexShift),
    2177     SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
    2178     SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
    2179     SSMFIELD_ENTRY_TERM()
    2180 };
    2181 
    2182 
    2183 /**
    2184  * @callback_method_impl{FNSSMDEVSAVEEXEC}
    2185  */
    2186 static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
    2187 {
    2188     ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
    2189     return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
    2190 }
    2191 
    2192 /**
    2193  * @callback_method_impl{FNSSMDEVLOADEXEC}
    2194  */
    2195 static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
    2196                                        uint32_t uVersion, uint32_t uPass)
    2197 {
    2198     ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
    2199     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
    2200 
    2201     /*
    2202      * Unregister PM handlers, will register with actual base after state
    2203      * successfully loaded.
    2204      */
    2205     int rc = acpiUnregisterPmHandlers(pThis);
    2206     if (RT_FAILURE(rc))
    2207         return rc;
    2208 
    2209     switch (uVersion)
    2210     {
    2211         case 4:
    2212             rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
    2213             break;
    2214         case 5:
    2215             rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
    2216             break;
    2217         case 6:
    2218             rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
    2219             break;
    2220         default:
    2221             rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    2222             break;
    2223     }
    2224     if (RT_SUCCESS(rc))
    2225     {
    2226         rc = acpiRegisterPmHandlers(pThis);
    2227         if (RT_FAILURE(rc))
    2228             return rc;
    2229         rc = acpiFetchBatteryStatus(pThis);
    2230         if (RT_FAILURE(rc))
    2231             return rc;
    2232         rc = acpiFetchBatteryInfo(pThis);
    2233         if (RT_FAILURE(rc))
    2234             return rc;
    2235         rc = acpiPMTimerReset(pThis);
    2236         if (RT_FAILURE(rc))
    2237             return rc;
    2238     }
    2239     return rc;
    2240 }
    2241 
    2242 /**
    2243  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    2244  */
    2245 static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    2246 {
    2247     ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
    2248     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
    2249     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
    2250     return NULL;
    2251 }
    2252 
    2253 /**
    2254  * Create the ACPI tables.
     2440/**
     2441 * Create the ACPI tables in guest memory.
    22552442 */
    22562443static int acpiPlantTables(ACPIState *s)
     
    22582445    int        rc;
    22592446    RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
    2260     RTGCPHYS32 GCPhysHpet = 0, GCPhysApic = 0, GCPhysSsdt = 0, GCPhysMcfg = 0;
     2447    RTGCPHYS32 GCPhysHpet = 0;
     2448    RTGCPHYS32 GCPhysApic = 0;
     2449    RTGCPHYS32 GCPhysSsdt = 0;
     2450    RTGCPHYS32 GCPhysMcfg = 0;
    22612451    uint32_t   addend = 0;
    22622452    RTGCPHYS32 aGCPhysRsdt[8];
    22632453    RTGCPHYS32 aGCPhysXsdt[8];
    2264     uint32_t   cAddr, iMadt = 0, iHpet = 0, iSsdt = 0, iMcfg = 0;
     2454    uint32_t   cAddr;
     2455    uint32_t   iMadt  = 0;
     2456    uint32_t   iHpet  = 0;
     2457    uint32_t   iSsdt  = 0;
     2458    uint32_t   iMcfg  = 0;
    22652459    size_t     cbRsdt = sizeof(ACPITBLHEADER);
    22662460    size_t     cbXsdt = sizeof(ACPITBLHEADER);
     
    23422536    }
    23432537
    2344     void*  pSsdtCode = NULL;
     2538    void  *pvSsdtCode = NULL;
    23452539    size_t cbSsdtSize = 0;
    2346     rc = acpiPrepareSsdt(s->pDevIns, &pSsdtCode, &cbSsdtSize);
     2540    rc = acpiPrepareSsdt(s->pDevIns, &pvSsdtCode, &cbSsdtSize);
    23472541    if (RT_FAILURE(rc))
    23482542        return rc;
     
    23532547    GCPhysDsdt = GCPhysCur;
    23542548
    2355     void*  pDsdtCode = NULL;
     2549    void  *pvDsdtCode = NULL;
    23562550    size_t cbDsdtSize = 0;
    2357     rc = acpiPrepareDsdt(s->pDevIns, &pDsdtCode, &cbDsdtSize);
     2551    rc = acpiPrepareDsdt(s->pDevIns, &pvDsdtCode, &cbDsdtSize);
    23582552    if (RT_FAILURE(rc))
    23592553        return rc;
     
    23802574
    23812575    acpiSetupRSDP((ACPITBLRSDP*)s->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
    2382     acpiSetupDSDT(s, GCPhysDsdt + addend, pDsdtCode, cbDsdtSize);
    2383     acpiCleanupDsdt(s->pDevIns, pDsdtCode);
     2576    acpiSetupDSDT(s, GCPhysDsdt + addend, pvDsdtCode, cbDsdtSize);
     2577    acpiCleanupDsdt(s->pDevIns, pvDsdtCode);
    23842578    acpiSetupFACS(s, GCPhysFacs + addend);
    23852579    acpiSetupFADT(s, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
     
    24062600    }
    24072601
    2408     acpiSetupSSDT(s, GCPhysSsdt + addend, pSsdtCode, cbSsdtSize);
    2409     acpiCleanupSsdt(s->pDevIns, pSsdtCode);
     2602    acpiSetupSSDT(s, GCPhysSsdt + addend, pvSsdtCode, cbSsdtSize);
     2603    acpiCleanupSsdt(s->pDevIns, pvSsdtCode);
    24102604    aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
    24112605    aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
     
    24172611}
    24182612
    2419 static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT uNewBase)
    2420 {
    2421     Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, uNewBase));
    2422     if (uNewBase != pThis->uPmIoPortBase)
    2423     {
    2424         int rc;
    2425 
    2426         rc = acpiUnregisterPmHandlers(pThis);
    2427         if (RT_FAILURE(rc))
    2428             return rc;
    2429 
    2430         pThis->uPmIoPortBase = uNewBase;
    2431 
    2432         rc = acpiRegisterPmHandlers(pThis);
    2433         if (RT_FAILURE(rc))
    2434             return rc;
    2435 
    2436         /* We have to update FADT table acccording to the new base */
    2437         rc = acpiPlantTables(pThis);
    2438         AssertRC(rc);
    2439         if (RT_FAILURE(rc))
    2440             return rc;
    2441     }
    2442 
    2443     return VINF_SUCCESS;
    2444 }
    2445 
    2446 static uint32_t acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
     2613/**
     2614 * @callback_method_impl{FNPCICONFIGREAD}
     2615 */
     2616static DECLCALLBACK(uint32_t) acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
    24472617{
    24482618    PPDMDEVINS pDevIns = pPciDev->pDevIns;
    2449     ACPIState*  pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     2619    ACPIState *pThis  = PDMINS_2_DATA(pDevIns, ACPIState *);
    24502620
    24512621    Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
    2452 
    24532622    return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
    24542623}
    24552624
    2456 static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
     2625/**
     2626 * @callback_method_impl{FNPCICONFIGWRITE}
     2627 */
     2628static DECLCALLBACK(void) acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
    24572629{
    24582630    PPDMDEVINS  pDevIns = pPciDev->pDevIns;
     
    24602632
    24612633    Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
    2462 
     2634    DEVACPI_LOCK_R3(pThis);
    24632635
    24642636    if (Address == VBOX_PCI_INTERRUPT_LINE)
     
    24762648        if (pPciDev->config[0x80] & 0x1)
    24772649        {
    2478             int rc;
    2479 
    2480             RTIOPORT uNewBase = RTIOPORT(PCIDevGetDWord(pPciDev, 0x40));
    2481             uNewBase &= 0xffc0;
    2482 
    2483             rc = acpiUpdatePmHandlers(pThis, uNewBase);
     2650            RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
     2651            NewIoPortBase &= 0xffc0;
     2652
     2653            int rc = acpiUpdatePmHandlers(pThis, NewIoPortBase);
    24842654            AssertRC(rc);
    24852655        }
    24862656    }
     2657
     2658    DEVACPI_UNLOCK(pThis);
    24872659}
    24882660
     
    25002672{
    25012673    ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
    2502 
    25032674    LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
    25042675
     
    25092680
    25102681    /* Check if it was already attached */
    2511     if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
    2512         return VINF_SUCCESS;
    2513 
    2514     PPDMIBASE IBaseTmp;
    2515     int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
    2516 
    2517     if (RT_SUCCESS(rc))
    2518     {
    2519         /* Enable the CPU */
    2520         VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
    2521 
    2522         /*
    2523          * Lock the CPU because we don't know if the guest will use it or not.
    2524          * Prevents ejection while the CPU is still used
    2525          */
    2526         VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
    2527         s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
    2528         s->u32CpuEvent     = iLUN;
    2529         /* Notify the guest */
    2530         update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
    2531     }
     2682    int rc = VINF_SUCCESS;
     2683    DEVACPI_LOCK_R3(s);
     2684    if (!VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
     2685    {
     2686        PPDMIBASE IBaseTmp;
     2687        rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
     2688        if (RT_SUCCESS(rc))
     2689        {
     2690            /* Enable the CPU */
     2691            VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
     2692
     2693            /*
     2694             * Lock the CPU because we don't know if the guest will use it or not.
     2695             * Prevents ejection while the CPU is still used
     2696             */
     2697            VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
     2698            s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
     2699            s->u32CpuEvent     = iLUN;
     2700
     2701            /* Notify the guest */
     2702            update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
     2703        }
     2704    }
     2705    DEVACPI_UNLOCK(s);
    25322706    return rc;
    25332707}
     
    25502724
    25512725    /* Check if it was already detached */
     2726    DEVACPI_LOCK_R3(s);
    25522727    if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
    25532728    {
    2554         AssertMsgReturnVoid(!(VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN)), ("CPU is still locked by the guest\n"));
    2555 
    2556         /* Disable the CPU */
    2557         VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
    2558         s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
    2559         s->u32CpuEvent     = iLUN;
    2560         /* Notify the guest */
    2561         update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
    2562     }
     2729        if (!VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN))
     2730        {
     2731            /* Disable the CPU */
     2732            VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
     2733            s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
     2734            s->u32CpuEvent     = iLUN;
     2735
     2736            /* Notify the guest */
     2737            update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
     2738        }
     2739        else
     2740            AssertMsgFailed(("CPU is still locked by the guest\n"));
     2741    }
     2742    DEVACPI_UNLOCK(s);
    25632743}
    25642744
     
    25822762static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
    25832763{
    2584     ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
    2585 
    2586     s->pm1a_en           = 0;
    2587     s->pm1a_sts          = 0;
    2588     s->pm1a_ctl          = 0;
    2589     s->u64PmTimerInitial = TMTimerGet(s->CTX_SUFF(ts));
    2590     acpiPMTimerReset(s);
    2591     s->uBatteryIndex     = 0;
    2592     s->uSystemInfoIndex  = 0;
    2593     s->gpe0_en           = 0;
    2594     s->gpe0_sts          = 0;
    2595     s->uSleepState       = 0;
     2764    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     2765
     2766    pThis->pm1a_en           = 0;
     2767    pThis->pm1a_sts          = 0;
     2768    pThis->pm1a_ctl          = 0;
     2769    pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
     2770    acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
     2771    pThis->uBatteryIndex     = 0;
     2772    pThis->uSystemInfoIndex  = 0;
     2773    pThis->gpe0_en           = 0;
     2774    pThis->gpe0_sts          = 0;
     2775    pThis->uSleepState       = 0;
    25962776
    25972777    /** @todo Should we really reset PM base? */
    2598     acpiUpdatePmHandlers(s, PM_PORT_BASE);
    2599 
    2600     acpiPlantTables(s);
     2778    acpiUpdatePmHandlers(pThis, PM_PORT_BASE);
     2779
     2780    acpiPlantTables(pThis);
    26012781}
    26022782
     
    26062786static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
    26072787{
    2608     ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
    2609     s->tsRC = TMTimerRCPtr(s->CTX_SUFF(ts));
     2788    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     2789    pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
    26102790}
    26112791
     
    26192799    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
    26202800
    2621     /* Validate and read the configuration. */
     2801    /*
     2802     * Init data and set defaults.
     2803     */
     2804    /** @todo move more of the code up! */
     2805
     2806    pDevIns->pCritSectR3 = PDMDevHlpCritSectGetNop(pDevIns);
     2807    int rc = PDMDevHlpCritSectInit(pDevIns, &s->CritSect, RT_SRC_POS, "acpi");
     2808    AssertRCReturn(rc, rc);
     2809
     2810    /*
     2811     * Validate and read the configuration.
     2812     */
    26222813    if (!CFGMR3AreValuesValid(pCfg,
    26232814                              "RamSize\0"
     
    26552846
    26562847    /* query whether we are supposed to present an IOAPIC */
    2657     int rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
     2848    rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
    26582849    if (RT_FAILURE(rc))
    26592850        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    27952986    s->IBase.pfnQueryInterface              = acpiQueryInterface;
    27962987    /* IACPIPort */
    2797     s->IACPIPort.pfnSleepButtonPress        = acpiSleepButtonPress;
    2798     s->IACPIPort.pfnPowerButtonPress        = acpiPowerButtonPress;
    2799     s->IACPIPort.pfnGetPowerButtonHandled   = acpiGetPowerButtonHandled;
    2800     s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
    2801     s->IACPIPort.pfnGetCpuStatus            = acpiGetCpuStatus;
     2988    s->IACPIPort.pfnSleepButtonPress        = acpiPort_SleepButtonPress;
     2989    s->IACPIPort.pfnPowerButtonPress        = acpiPort_PowerButtonPress;
     2990    s->IACPIPort.pfnGetPowerButtonHandled   = acpiPort_GetPowerButtonHandled;
     2991    s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiPort_GetGuestEnteredACPIMode;
     2992    s->IACPIPort.pfnGetCpuStatus            = acpiPort_GetCpuStatus;
    28022993
    28032994    VMCPUSET_EMPTY(&s->CpuSetAttached);
     
    28873078#undef R
    28883079
    2889     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, dev,
    2890                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "ACPI Timer", &s->tsR3);
     3080    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiPmTimer, dev,
     3081                                TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &s->pPmTimerR3);
    28913082    if (RT_FAILURE(rc))
    28923083    {
     
    28953086    }
    28963087
    2897     s->tsR0 = TMTimerR0Ptr(s->tsR3);
    2898     s->tsRC = TMTimerRCPtr(s->tsR3);
    2899     s->u64PmTimerInitial = TMTimerGet(s->tsR3);
    2900     acpiPMTimerReset(s);
     3088    s->pPmTimerR0 = TMTimerR0Ptr(s->pPmTimerR3);
     3089    s->pPmTimerRC = TMTimerRCPtr(s->pPmTimerR3);
     3090    s->u64PmTimerInitial = TMTimerGet(s->pPmTimerR3);
     3091    acpiPmTimerReset(s, s->u64PmTimerInitial);
    29013092
    29023093    PCIDevSetVendorId(dev, 0x8086); /* Intel */
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r37430 r37444  
    481481    GEN_CHECK_OFF(ACPIState, pm1a_ctl);
    482482    GEN_CHECK_OFF(ACPIState, u64PmTimerInitial);
    483     GEN_CHECK_OFF(ACPIState, tsR3);
    484     GEN_CHECK_OFF(ACPIState, tsR0);
    485     GEN_CHECK_OFF(ACPIState, tsRC);
     483    GEN_CHECK_OFF(ACPIState, pPmTimerR3);
     484    GEN_CHECK_OFF(ACPIState, pPmTimerR0);
     485    GEN_CHECK_OFF(ACPIState, pPmTimerRC);
    486486    GEN_CHECK_OFF(ACPIState, gpe0_en);
    487487    GEN_CHECK_OFF(ACPIState, gpe0_sts);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette