summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/PC/DevPit-i8254.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/PC/DevPit-i8254.cpp')
-rw-r--r--src/VBox/Devices/PC/DevPit-i8254.cpp211
1 files changed, 129 insertions, 82 deletions
diff --git a/src/VBox/Devices/PC/DevPit-i8254.cpp b/src/VBox/Devices/PC/DevPit-i8254.cpp
index 4987cc251..090548311 100644
--- a/src/VBox/Devices/PC/DevPit-i8254.cpp
+++ b/src/VBox/Devices/PC/DevPit-i8254.cpp
@@ -1,10 +1,10 @@
-/* $Id: DevPit-i8254.cpp $ */
+/* $Id: DevPit-i8254.cpp 29250 2010-05-09 17:53:58Z vboxsync $ */
/** @file
* DevPIT-i8254 - Intel 8254 Programmable Interval Timer (PIT) And Dummy Speaker Device.
*/
/*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ * Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -13,10 +13,6 @@
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
* --------------------------------------------------------------------
*
* This code is based on:
@@ -52,7 +48,13 @@
#include <VBox/log.h>
#include <VBox/stam.h>
#include <iprt/assert.h>
-#include <iprt/asm.h>
+#include <iprt/asm-math.h>
+
+#ifdef IN_RING3
+# include <iprt/alloc.h>
+# include <iprt/string.h>
+# include <iprt/uuid.h>
+#endif /* IN_RING3 */
#include "../Builtins.h"
@@ -69,7 +71,10 @@
#define RW_STATE_WORD1 4
/** The current saved state version. */
-#define PIT_SAVED_STATE_VERSION 3
+#define PIT_SAVED_STATE_VERSION 4
+/** The saved state version used by VirtualBox 3.1 and earlier.
+ * This did not include disable by HPET flag. */
+#define PIT_SAVED_STATE_VERSION_VBOX_31 3
/** The saved state version used by VirtualBox 3.0 and earlier.
* This did not include the config part. */
#define PIT_SAVED_STATE_VERSION_VBOX_30 2
@@ -146,7 +151,10 @@ typedef struct PITState
RTIOPORT IOPortBaseCfg;
/** Config: Speaker enabled. */
bool fSpeakerCfg;
- bool afAlignment0[HC_ARCH_BITS == 32 ? 1 : 5];
+ bool fDisabledByHpet;
+ bool afAlignment0[HC_ARCH_BITS == 32 ? 4 : 4];
+ /** PIT port interface. */
+ PDMIHPETLEGACYNOTIFY IHpetLegacyNotify;
/** Pointer to the device instance. */
PPDMDEVINSR3 pDevIns;
/** Number of IRQs that's been raised. */
@@ -413,9 +421,18 @@ static void pit_irq_timer_update(PITChannelState *s, uint64_t current_time, uint
/* We just flip-flop the irq level to save that extra timer call, which isn't generally required (we haven't served it for months). */
pDevIns = s->CTX_SUFF(pPit)->pDevIns;
- PDMDevHlpISASetIrq(pDevIns, s->irq, irq_level);
- if (irq_level)
- PDMDevHlpISASetIrq(pDevIns, s->irq, 0);
+
+ /* If PIT disabled by HPET - just disconnect ticks from interrupt controllers, and not modify
+ * other moments of device functioning.
+ * @todo: is it correct?
+ */
+ if (!s->pPitR3->fDisabledByHpet)
+ {
+ PDMDevHlpISASetIrq(pDevIns, s->irq, irq_level);
+ if (irq_level)
+ PDMDevHlpISASetIrq(pDevIns, s->irq, 0);
+ }
+
if (irq_level)
{
s->u64ReloadTS = now;
@@ -763,10 +780,12 @@ static DECLCALLBACK(int) pitSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
SSMR3PutS32(pSSM, pThis->speaker_data_on);
#ifdef FAKE_REFRESH_CLOCK
- return SSMR3PutS32(pSSM, pThis->dummy_refresh_clock);
+ SSMR3PutS32(pSSM, pThis->dummy_refresh_clock);
#else
- return SSMR3PutS32(pSSM, 0);
+ SSMR3PutS32(pSSM, 0);
#endif
+
+ return SSMR3PutBool(pSSM, pThis->fDisabledByHpet);
}
@@ -779,7 +798,8 @@ static DECLCALLBACK(int) pitLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
int rc;
if ( uVersion != PIT_SAVED_STATE_VERSION
- && uVersion != PIT_SAVED_STATE_VERSION_VBOX_30)
+ && uVersion != PIT_SAVED_STATE_VERSION_VBOX_30
+ && uVersion != PIT_SAVED_STATE_VERSION_VBOX_31)
return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
/* The config. */
@@ -838,11 +858,15 @@ static DECLCALLBACK(int) pitLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
SSMR3GetS32(pSSM, &pThis->speaker_data_on);
#ifdef FAKE_REFRESH_CLOCK
- return SSMR3GetS32(pSSM, &pThis->dummy_refresh_clock);
+ SSMR3GetS32(pSSM, &pThis->dummy_refresh_clock);
#else
int32_t u32Dummy;
- return SSMR3GetS32(pSSM, &u32Dummy);
+ SSMR3GetS32(pSSM, &u32Dummy);
#endif
+ if (uVersion > PIT_SAVED_STATE_VERSION_VBOX_31)
+ SSMR3GetBool(pSSM, &pThis->fDisabledByHpet);
+
+ return VINF_SUCCESS;
}
@@ -864,6 +888,72 @@ static DECLCALLBACK(void) pitTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pv
/**
+ * Info handler, device version.
+ *
+ * @param pDevIns Device instance which registered the info.
+ * @param pHlp Callback functions for doing output.
+ * @param pszArgs Argument string. Optional and specific to the handler.
+ */
+static DECLCALLBACK(void) pitInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+ PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
+ {
+ const PITChannelState *pCh = &pThis->channels[i];
+
+ pHlp->pfnPrintf(pHlp,
+ "PIT (i8254) channel %d status: irq=%#x\n"
+ " count=%08x" " latched_count=%04x count_latched=%02x\n"
+ " status=%02x status_latched=%02x read_state=%02x\n"
+ " write_state=%02x write_latch=%02x rw_mode=%02x\n"
+ " mode=%02x bcd=%02x gate=%02x\n"
+ " count_load_time=%016RX64 next_transition_time=%016RX64\n"
+ " u64ReloadTS=%016RX64 u64NextTS=%016RX64\n"
+ ,
+ i, pCh->irq,
+ pCh->count, pCh->latched_count, pCh->count_latched,
+ pCh->status, pCh->status_latched, pCh->read_state,
+ pCh->write_state, pCh->write_latch, pCh->rw_mode,
+ pCh->mode, pCh->bcd, pCh->gate,
+ pCh->count_load_time, pCh->next_transition_time,
+ pCh->u64ReloadTS, pCh->u64NextTS);
+ }
+#ifdef FAKE_REFRESH_CLOCK
+ pHlp->pfnPrintf(pHlp, "speaker_data_on=%#x dummy_refresh_clock=%#x\n",
+ pThis->speaker_data_on, pThis->dummy_refresh_clock);
+#else
+ pHlp->pfnPrintf(pHlp, "speaker_data_on=%#x\n", pThis->speaker_data_on);
+#endif
+ if (pThis->fDisabledByHpet)
+ pHlp->pfnPrintf(pHlp, "Disabled by HPET\n");
+}
+
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) pitQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
+ PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHPETLEGACYNOTIFY, &pThis->IHpetLegacyNotify);
+ return NULL;
+}
+
+
+/**
+ * @interface_method_impl{PDMIHPETLEGACYNOTIFY,pfnModeChanged}
+ */
+static DECLCALLBACK(void) pitNotifyHpetLegacyNotify_ModeChanged(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)
+{
+ PITState *pThis = RT_FROM_MEMBER(pInterface, PITState, IHpetLegacyNotify);
+ pThis->fDisabledByHpet = fActivated;
+}
+
+
+/**
* Relocation notification.
*
* @returns VBox status.
@@ -885,8 +975,6 @@ static DECLCALLBACK(void) pitRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
}
}
-/** @todo remove this! */
-static DECLCALLBACK(void) pitInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
/**
* Reset notification.
@@ -900,6 +988,8 @@ static DECLCALLBACK(void) pitReset(PPDMDEVINS pDevIns)
unsigned i;
LogFlow(("pitReset: \n"));
+ pThis->fDisabledByHpet = false;
+
for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
{
PITChannelState *s = &pThis->channels[i];
@@ -925,60 +1015,9 @@ static DECLCALLBACK(void) pitReset(PPDMDEVINS pDevIns)
/**
- * Info handler, device version.
- *
- * @param pDevIns Device instance which registered the info.
- * @param pHlp Callback functions for doing output.
- * @param pszArgs Argument string. Optional and specific to the handler.
+ * @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
-static DECLCALLBACK(void) pitInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
- unsigned i;
- for (i = 0; i < RT_ELEMENTS(pThis->channels); i++)
- {
- const PITChannelState *pCh = &pThis->channels[i];
-
- pHlp->pfnPrintf(pHlp,
- "PIT (i8254) channel %d status: irq=%#x\n"
- " count=%08x" " latched_count=%04x count_latched=%02x\n"
- " status=%02x status_latched=%02x read_state=%02x\n"
- " write_state=%02x write_latch=%02x rw_mode=%02x\n"
- " mode=%02x bcd=%02x gate=%02x\n"
- " count_load_time=%016RX64 next_transition_time=%016RX64\n"
- " u64ReloadTS=%016RX64 u64NextTS=%016RX64\n"
- ,
- i, pCh->irq,
- pCh->count, pCh->latched_count, pCh->count_latched,
- pCh->status, pCh->status_latched, pCh->read_state,
- pCh->write_state, pCh->write_latch, pCh->rw_mode,
- pCh->mode, pCh->bcd, pCh->gate,
- pCh->count_load_time, pCh->next_transition_time,
- pCh->u64ReloadTS, pCh->u64NextTS);
- }
-#ifdef FAKE_REFRESH_CLOCK
- pHlp->pfnPrintf(pHlp, "speaker_data_on=%#x dummy_refresh_clock=%#x\n",
- pThis->speaker_data_on, pThis->dummy_refresh_clock);
-#else
- pHlp->pfnPrintf(pHlp, "speaker_data_on=%#x\n", pThis->speaker_data_on);
-#endif
-}
-
-
-/**
- * Construct a device instance for a VM.
- *
- * @returns VBox status.
- * @param pDevIns The device instance data.
- * If the registration structure is needed, pDevIns->pDevReg points to it.
- * @param iInstance Instance number. Use this to figure out which registers and such to use.
- * The device number is also found in pDevIns->iInstance, but since it's
- * likely to be freqently used PDM passes it as parameter.
- * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
- * of the device instance. It's also found in pDevIns->pCfgHandle, but like
- * iInstance it's expected to be used a bit in this function.
- */
-static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
+static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
PITState *pThis = PDMINS_2_DATA(pDevIns, PITState *);
int rc;
@@ -993,33 +1032,33 @@ static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
/*
* Validate configuration.
*/
- if (!CFGMR3AreValuesValid(pCfgHandle, "Irq\0" "Base\0" "SpeakerEnabled\0" "GCEnabled\0" "R0Enabled\0"))
+ if (!CFGMR3AreValuesValid(pCfg, "Irq\0" "Base\0" "SpeakerEnabled\0" "GCEnabled\0" "R0Enabled\0"))
return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
/*
* Init the data.
*/
- rc = CFGMR3QueryU8Def(pCfgHandle, "Irq", &u8Irq, 0);
+ rc = CFGMR3QueryU8Def(pCfg, "Irq", &u8Irq, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"Irq\" as a uint8_t failed"));
- rc = CFGMR3QueryU16Def(pCfgHandle, "Base", &u16Base, 0x40);
+ rc = CFGMR3QueryU16Def(pCfg, "Base", &u16Base, 0x40);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"Base\" as a uint16_t failed"));
- rc = CFGMR3QueryBoolDef(pCfgHandle, "SpeakerEnabled", &fSpeaker, true);
+ rc = CFGMR3QueryBoolDef(pCfg, "SpeakerEnabled", &fSpeaker, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"SpeakerEnabled\" as a bool failed"));
- rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
+ rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
- rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
+ rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: failed to read R0Enabled as boolean"));
@@ -1036,6 +1075,14 @@ static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
}
/*
+ * Interfaces
+ */
+ /* IBase */
+ pDevIns->IBase.pfnQueryInterface = pitQueryInterface;
+ /* IHpetLegacyNotify */
+ pThis->IHpetLegacyNotify.pfnModeChanged = pitNotifyHpetLegacyNotify_ModeChanged;
+
+ /*
* Create timer, register I/O Ports and save state.
*/
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, pitTimer, &pThis->channels[0],
@@ -1051,7 +1098,7 @@ static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
return rc;
if (fGCEnabled)
{
- rc = PDMDevHlpIOPortRegisterGC(pDevIns, u16Base, 4, 0, "pitIOPortWrite", "pitIOPortRead", NULL, NULL, "i8254 Programmable Interval Timer");
+ rc = PDMDevHlpIOPortRegisterRC(pDevIns, u16Base, 4, 0, "pitIOPortWrite", "pitIOPortRead", NULL, NULL, "i8254 Programmable Interval Timer");
if (RT_FAILURE(rc))
return rc;
}
@@ -1069,7 +1116,7 @@ static DECLCALLBACK(int) pitConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
return rc;
if (fGCEnabled)
{
- rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x61, 1, 0, NULL, "pitIOPortSpeakerRead", NULL, NULL, "PC Speaker");
+ rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x61, 1, 0, NULL, "pitIOPortSpeakerRead", NULL, NULL, "PC Speaker");
if (RT_FAILURE(rc))
return rc;
}
@@ -1103,7 +1150,7 @@ const PDMDEVREG g_DeviceI8254 =
{
/* u32Version */
PDM_DEVREG_VERSION,
- /* szDeviceName */
+ /* szName */
"i8254",
/* szRCMod */
"VBoxDDGC.gc",
@@ -1139,7 +1186,7 @@ const PDMDEVREG g_DeviceI8254 =
NULL,
/* pfnDetach */
NULL,
- /* pfnQueryInterface. */
+ /* pfnQueryInterface */
NULL,
/* pfnInitComplete */
NULL,