summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/testcase/tstRTR0CommonDriver.h')
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0CommonDriver.h292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h b/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
new file mode 100644
index 00000000..157c0c71
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTR0CommonDriver.h
@@ -0,0 +1,292 @@
+/* $Id: tstRTR0CommonDriver.h $ */
+/** @file
+ * IPRT R0 Testcase - Common header for the testcase drivers.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef IPRT_INCLUDED_SRC_testcase_tstRTR0CommonDriver_h
+#define IPRT_INCLUDED_SRC_testcase_tstRTR0CommonDriver_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/ctype.h>
+#include <iprt/string.h>
+#include <VBox/sup.h>
+#include "tstRTR0CommonReq.h"
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The test handle. */
+RTTEST g_hTest;
+/** The test & service name. */
+char g_szSrvName[64];
+/** The length of the service name. */
+size_t g_cchSrvName;
+/** The base address of the service module. */
+void *g_pvImageBase;
+
+
+/**
+ * Initializes the test driver.
+ *
+ * This means creating a test instance (RTTEST), initializing the support
+ * library, and loading the service module.
+ *
+ * @returns RTEXITCODE_SUCCESS on success, appropriate exit code on failure.
+ * @param pszTestServiceName The name of the test and service. This
+ * will be used when creating the test
+ * instance as well as when talking with the
+ * kernel side of the test.
+ *
+ * The ring-0 module name will be derived from
+ * this + '.r0'.
+ *
+ * The service request handler function name
+ * will be derived by upper casing the first
+ * chars and appending 'SrvReqHandler'.
+ *
+ */
+RTEXITCODE RTR3TestR0CommonDriverInit(const char *pszTestServiceName)
+{
+ /*
+ * Init the test.
+ */
+ RTEXITCODE rcExit = RTTestInitAndCreate(pszTestServiceName, &g_hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(g_hTest);
+
+ /*
+ * Init the globals.
+ */
+ g_cchSrvName = strlen(pszTestServiceName);
+ int rc = RTStrCopy(g_szSrvName, sizeof(g_szSrvName), pszTestServiceName);
+ if (rc != VINF_SUCCESS)
+ {
+ RTTestFailed(g_hTest, "The test name is too long! (%zu bytes)", g_cchSrvName);
+ return RTTestSummaryAndDestroy(g_hTest);
+ }
+
+ /*
+ * Initialize the support driver session.
+ */
+ PSUPDRVSESSION pSession;
+ rc = SUPR3Init(&pSession);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "SUPR3Init failed with rc=%Rrc\n", rc);
+ return RTTestSummaryAndDestroy(g_hTest);
+ }
+
+ char szPath[RTPATH_MAX + sizeof(".r0")];
+ rc = RTPathExecDir(szPath, RTPATH_MAX);
+ if (RT_SUCCESS(rc))
+ rc = RTPathAppend(szPath, RTPATH_MAX, pszTestServiceName);
+ if (RT_SUCCESS(rc))
+ strcat(szPath, ".r0");
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "Failed constructing .r0 filename (rc=%Rrc)", rc);
+ return RTTestSummaryAndDestroy(g_hTest);
+ }
+
+ char szSrvReqHandler[sizeof(g_szSrvName) + sizeof("SrvReqHandler")];
+ strcpy(szSrvReqHandler, pszTestServiceName);
+ strcat(szSrvReqHandler, "SrvReqHandler");
+ for (size_t off = 0; RT_C_IS_LOWER(szSrvReqHandler[off]); off++)
+ szSrvReqHandler[off] = RT_C_TO_UPPER(szSrvReqHandler[off]);
+
+ rc = SUPR3LoadServiceModule(szPath, pszTestServiceName, szSrvReqHandler, &g_pvImageBase);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "SUPR3LoadServiceModule(%s,%s,%s,) failed with rc=%Rrc\n",
+ szPath, pszTestServiceName, szSrvReqHandler, rc);
+ return RTTestSummaryAndDestroy(g_hTest);
+ }
+
+ /*
+ * Do the sanity checks.
+ */
+ RTTestSub(g_hTest, "Sanity");
+ RTTSTR0REQ Req;
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ memset(Req.szMsg, 0xef, sizeof(Req.szMsg));
+ RTTESTI_CHECK_RC(rc = SUPR3CallR0Service(g_szSrvName, g_cchSrvName, RTTSTR0REQ_SANITY_OK, 0, &Req.Hdr), VINF_SUCCESS);
+ if (RT_FAILURE(rc))
+ return RTTestSummaryAndDestroy(g_hTest);
+ RTTESTI_CHECK_MSG(Req.szMsg[0] == '\0', ("%s", Req.szMsg));
+ if (Req.szMsg[0] != '\0')
+ return RTTestSummaryAndDestroy(g_hTest);
+
+
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ Req.szMsg[0] = '\0';
+ memset(Req.szMsg, 0xfe, sizeof(Req.szMsg));
+ RTTESTI_CHECK_RC(rc = SUPR3CallR0Service(g_szSrvName, g_cchSrvName, RTTSTR0REQ_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
+ if (RT_FAILURE(rc))
+ return RTTestSummaryAndDestroy(g_hTest);
+ rc = !strncmp(Req.szMsg, "!42failure42", sizeof("!42failure42"));
+ if (rc)
+ {
+ RTTestFailed(g_hTest, "the negative sanity check failed");
+ return RTTestSummaryAndDestroy(g_hTest);
+ }
+ RTTestSubDone(g_hTest);
+
+ return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Processes the messages in the request.
+ *
+ * @returns true on success, false on failure.
+ * @param pReq The request.
+ */
+static bool rtR3TestR0ProcessMessages(PRTTSTR0REQ pReq)
+{
+ /*
+ * Process the message strings.
+ *
+ * We can have multiple failures and info messages packed into szMsg. They
+ * are separated by a double newline. The kind of message is indicated by
+ * the first character, '!' means error and '?' means info message. '$' means
+ * the test was skipped because a feature is not supported on the host.
+ */
+ bool fRc = true;
+ if (pReq->szMsg[0])
+ {
+ pReq->szMsg[sizeof(pReq->szMsg) - 1] = '\0'; /* paranoia */
+
+ char *pszNext = &pReq->szMsg[0];
+ do
+ {
+ char *pszCur = pszNext;
+ do
+ pszNext = strpbrk(pszNext + 1, "!?$");
+ while (pszNext && (pszNext[-1] != '\n' || pszNext[-2] != '\n'));
+
+ char *pszEnd = pszNext ? pszNext - 1 : strchr(pszCur, '\0');
+ while ( (uintptr_t)pszEnd > (uintptr_t)pszCur
+ && pszEnd[-1] == '\n')
+ *--pszEnd = '\0';
+
+ if (*pszCur == '!')
+ {
+ RTTestFailed(g_hTest, "%s", pszCur + 1);
+ fRc = false;
+ }
+ else if (*pszCur == '$')
+ {
+ RTTestSkipped(g_hTest, "%s", pszCur + 1);
+ }
+ else
+ RTTestPrintfNl(g_hTest, RTTESTLVL_ALWAYS, "%s", pszCur + 1);
+ } while (pszNext);
+ }
+
+ return fRc;
+}
+
+
+/**
+ * Performs a simple test with an argument (@a u64Arg).
+ *
+ * @returns true on success, false on failure.
+ * @param uOperation The operation to perform.
+ * @param u64Arg 64-bit argument.
+ * @param pszTestFmt The sub-test name.
+ * @param ... Format arguments.
+ */
+bool RTR3TestR0SimpleTestWithArg(uint32_t uOperation, uint64_t u64Arg, const char *pszTestFmt, ...)
+{
+ va_list va;
+ va_start(va, pszTestFmt);
+ RTTestSubV(g_hTest, pszTestFmt, va);
+ va_end(va);
+
+ RTTSTR0REQ Req;
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ RT_ZERO(Req.szMsg);
+ int rc = SUPR3CallR0Service(g_szSrvName, g_cchSrvName, uOperation, u64Arg, &Req.Hdr);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "SUPR3CallR0Service failed with rc=%Rrc", rc);
+ return false;
+ }
+
+ return rtR3TestR0ProcessMessages(&Req);
+}
+
+
+/**
+ * Performs a simple test.
+ *
+ * @returns true on success, false on failure.
+ * @param uOperation The operation to perform.
+ * @param pszTestFmt The sub-test name.
+ * @param ... Format arguments.
+ */
+bool RTR3TestR0SimpleTest(uint32_t uOperation, const char *pszTestFmt, ...)
+{
+ va_list va;
+ va_start(va, pszTestFmt);
+ RTTestSubV(g_hTest, pszTestFmt, va);
+ va_end(va);
+
+ RTTSTR0REQ Req;
+ Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
+ Req.Hdr.cbReq = sizeof(Req);
+ RT_ZERO(Req.szMsg);
+ int rc = SUPR3CallR0Service(g_szSrvName, g_cchSrvName, uOperation, 0, &Req.Hdr);
+ if (RT_FAILURE(rc))
+ {
+ RTTestFailed(g_hTest, "SUPR3CallR0Service failed with rc=%Rrc", rc);
+ return false;
+ }
+
+ return rtR3TestR0ProcessMessages(&Req);
+}
+
+#endif /* !IPRT_INCLUDED_SRC_testcase_tstRTR0CommonDriver_h */
+