summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Serial/DrvRawFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Serial/DrvRawFile.cpp')
-rw-r--r--src/VBox/Devices/Serial/DrvRawFile.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/VBox/Devices/Serial/DrvRawFile.cpp b/src/VBox/Devices/Serial/DrvRawFile.cpp
new file mode 100644
index 00000000..389da56a
--- /dev/null
+++ b/src/VBox/Devices/Serial/DrvRawFile.cpp
@@ -0,0 +1,297 @@
+/* $Id: DrvRawFile.cpp $ */
+/** @file
+ * VBox stream drivers - Raw file output.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEFAULT
+#include <VBox/vmm/pdmdrv.h>
+#include <iprt/assert.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/poll.h>
+#include <iprt/semaphore.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+
+#include "VBoxDD.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Raw file output driver instance data.
+ *
+ * @implements PDMISTREAM
+ */
+typedef struct DRVRAWFILE
+{
+ /** The stream interface. */
+ PDMISTREAM IStream;
+ /** Pointer to the driver instance. */
+ PPDMDRVINS pDrvIns;
+ /** Pointer to the file name. (Freed by MM) */
+ char *pszLocation;
+ /** File handle to write the data to. */
+ RTFILE hOutputFile;
+ /** Event semaphore for the poll interface. */
+ RTSEMEVENT hSemEvtPoll;
+} DRVRAWFILE, *PDRVRAWFILE;
+
+
+
+/* -=-=-=-=- PDMISTREAM -=-=-=-=- */
+
+/** @interface_method_impl{PDMISTREAM,pfnPoll} */
+static DECLCALLBACK(int) drvRawFilePoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)
+{
+ PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
+
+ Assert(!(fEvts & RTPOLL_EVT_READ)); /* Reading is not supported here. */
+
+ /* Writing is always possible. */
+ if (fEvts & RTPOLL_EVT_WRITE)
+ {
+ *pfEvts = RTPOLL_EVT_WRITE;
+ return VINF_SUCCESS;
+ }
+
+ return RTSemEventWait(pThis->hSemEvtPoll, cMillies);
+}
+
+
+/** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */
+static DECLCALLBACK(int) drvRawFilePollInterrupt(PPDMISTREAM pInterface)
+{
+ PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
+ return RTSemEventSignal(pThis->hSemEvtPoll);
+}
+
+
+/** @interface_method_impl{PDMISTREAM,pfnWrite} */
+static DECLCALLBACK(int) drvRawFileWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
+{
+ int rc = VINF_SUCCESS;
+ PDRVRAWFILE pThis = RT_FROM_MEMBER(pInterface, DRVRAWFILE, IStream);
+ LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
+
+ Assert(pvBuf);
+ if (pThis->hOutputFile != NIL_RTFILE)
+ {
+ size_t cbWritten;
+ rc = RTFileWrite(pThis->hOutputFile, pvBuf, *pcbWrite, &cbWritten);
+#if 0
+ /* don't flush here, takes too long and we will loose characters */
+ if (RT_SUCCESS(rc))
+ RTFileFlush(pThis->hOutputFile);
+#endif
+ *pcbWrite = cbWritten;
+ }
+
+ LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
+ return rc;
+}
+
+/* -=-=-=-=- PDMIBASE -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvRawFileQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
+ return NULL;
+}
+
+/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
+
+
+/**
+ * Power off a raw output stream driver instance.
+ *
+ * This does most of the destruction work, to avoid ordering dependencies.
+ *
+ * @param pDrvIns The driver instance data.
+ */
+static DECLCALLBACK(void) drvRawFilePowerOff(PPDMDRVINS pDrvIns)
+{
+ PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
+ LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
+
+ RTFileClose(pThis->hOutputFile);
+ pThis->hOutputFile = NIL_RTFILE;
+}
+
+
+/**
+ * Destruct a raw output stream driver instance.
+ *
+ * Most VM resources are freed by the VM. This callback is provided so that
+ * any non-VM resources can be freed correctly.
+ *
+ * @param pDrvIns The driver instance data.
+ */
+static DECLCALLBACK(void) drvRawFileDestruct(PPDMDRVINS pDrvIns)
+{
+ PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
+ LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+
+ if (pThis->pszLocation)
+ PDMDrvHlpMMHeapFree(pDrvIns, pThis->pszLocation);
+
+ if (pThis->hOutputFile != NIL_RTFILE)
+ {
+ RTFileClose(pThis->hOutputFile);
+ pThis->hOutputFile = NIL_RTFILE;
+ }
+
+ if (pThis->hSemEvtPoll != NIL_RTSEMEVENT)
+ {
+ RTSemEventDestroy(pThis->hSemEvtPoll);
+ pThis->hSemEvtPoll = NIL_RTSEMEVENT;
+ }
+}
+
+
+/**
+ * Construct a raw output stream driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvRawFileConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+ RT_NOREF(fFlags);
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ PDRVRAWFILE pThis = PDMINS_2_DATA(pDrvIns, PDRVRAWFILE);
+ PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
+
+ /*
+ * Init the static parts.
+ */
+ pThis->pDrvIns = pDrvIns;
+ pThis->pszLocation = NULL;
+ pThis->hOutputFile = NIL_RTFILE;
+ /* IBase */
+ pDrvIns->IBase.pfnQueryInterface = drvRawFileQueryInterface;
+ /* IStream */
+ pThis->IStream.pfnPoll = drvRawFilePoll;
+ pThis->IStream.pfnPollInterrupt = drvRawFilePollInterrupt;
+ pThis->IStream.pfnRead = NULL;
+ pThis->IStream.pfnWrite = drvRawFileWrite;
+
+ /*
+ * Read the configuration.
+ */
+ PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location", "");
+
+ int rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
+ if (RT_FAILURE(rc))
+ AssertMsgFailedReturn(("Configuration error: query \"Location\" resulted in %Rrc.\n", rc), rc);
+
+ rc = RTSemEventCreate(&pThis->hSemEvtPoll);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Open the raw file.
+ */
+ rc = RTFileOpen(&pThis->hOutputFile, pThis->pszLocation, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("RawFile%d: CreateFile failed rc=%Rrc\n", pDrvIns->iInstance, rc));
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("RawFile#%d failed to create the raw output file %s"), pDrvIns->iInstance, pThis->pszLocation);
+ }
+
+ LogFlow(("drvRawFileConstruct: location %s\n", pThis->pszLocation));
+ LogRel(("RawFile#%u: location %s\n", pDrvIns->iInstance, pThis->pszLocation));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Raw file driver registration record.
+ */
+const PDMDRVREG g_DrvRawFile =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "RawFile",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "RawFile stream driver.",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_STREAM,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVRAWFILE),
+ /* pfnConstruct */
+ drvRawFileConstruct,
+ /* pfnDestruct */
+ drvRawFileDestruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ drvRawFilePowerOff,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
+