summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/TMInline.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/include/TMInline.h')
-rw-r--r--src/VBox/VMM/include/TMInline.h289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/VBox/VMM/include/TMInline.h b/src/VBox/VMM/include/TMInline.h
new file mode 100644
index 00000000..ebc46229
--- /dev/null
+++ b/src/VBox/VMM/include/TMInline.h
@@ -0,0 +1,289 @@
+/* $Id: TMInline.h $ */
+/** @file
+ * TM - Common Inlined functions.
+ */
+
+/*
+ * 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
+ */
+
+#ifndef VMM_INCLUDED_SRC_include_TMInline_h
+#define VMM_INCLUDED_SRC_include_TMInline_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+
+DECLINLINE(PTMTIMER) tmTimerQueueGetHead(PTMTIMERQUEUECC pQueueCC, PTMTIMERQUEUE pQueueShared)
+{
+#ifdef IN_RING3
+ RT_NOREF(pQueueShared);
+ uint32_t const idx = pQueueCC->idxActive;
+#else
+ uint32_t const idx = pQueueShared->idxActive;
+#endif
+ if (idx < pQueueCC->cTimersAlloc)
+ return &pQueueCC->paTimers[idx];
+ return NULL;
+}
+
+
+DECLINLINE(void) tmTimerQueueSetHead(PTMTIMERQUEUECC pQueueCC, PTMTIMERQUEUE pQueueShared, PTMTIMER pHead)
+{
+ uint32_t idx;
+ if (pHead)
+ {
+ idx = (uint32_t)(pHead - &pQueueCC->paTimers[0]);
+ AssertMsgStmt(idx < pQueueCC->cTimersAlloc,
+ ("idx=%u (%s) cTimersAlloc=%u\n", idx, pHead->szName, pQueueCC->cTimersAlloc),
+ idx = UINT32_MAX);
+ }
+ else
+ idx = UINT32_MAX;
+#ifndef IN_RING3
+ pQueueShared->idxActive = idx;
+#else
+ pQueueCC->idxActive = idx;
+ RT_NOREF(pQueueShared);
+#endif
+}
+
+
+/**
+ * Get the previous timer - translates TMTIMER::idxPrev.
+ */
+DECLINLINE(PTMTIMER) tmTimerGetPrev(PTMTIMERQUEUECC pQueueCC, PTMTIMER pTimer)
+{
+ uint32_t const idxPrev = pTimer->idxPrev;
+ Assert(idxPrev);
+ if (idxPrev < pQueueCC->cTimersAlloc)
+ return &pQueueCC->paTimers[idxPrev];
+ Assert(idxPrev == UINT32_MAX);
+ return NULL;
+}
+
+
+/**
+ * Get the next timer - translates TMTIMER::idxNext.
+ */
+DECLINLINE(PTMTIMER) tmTimerGetNext(PTMTIMERQUEUECC pQueueCC, PTMTIMER pTimer)
+{
+ uint32_t const idxNext = pTimer->idxNext;
+ Assert(idxNext);
+ if (idxNext < pQueueCC->cTimersAlloc)
+ return &pQueueCC->paTimers[idxNext];
+ Assert(idxNext == UINT32_MAX);
+ return NULL;
+}
+
+
+/**
+ * Set the previous timer link (TMTIMER::idxPrev).
+ */
+DECLINLINE(void) tmTimerSetPrev(PTMTIMERQUEUECC pQueueCC, PTMTIMER pTimer, PTMTIMER pPrev)
+{
+ uint32_t idxPrev;
+ if (pPrev)
+ {
+ idxPrev = (uint32_t)(pPrev - &pQueueCC->paTimers[0]);
+ Assert(idxPrev);
+ AssertMsgStmt(idxPrev < pQueueCC->cTimersAlloc,
+ ("idxPrev=%u (%s) cTimersAlloc=%u\n", idxPrev, pPrev->szName, pQueueCC->cTimersAlloc),
+ idxPrev = UINT32_MAX);
+ }
+ else
+ idxPrev = UINT32_MAX;
+ pTimer->idxPrev = idxPrev;
+}
+
+
+/**
+ * Set the next timer link (TMTIMER::idxNext).
+ */
+DECLINLINE(void) tmTimerSetNext(PTMTIMERQUEUECC pQueueCC, PTMTIMER pTimer, PTMTIMER pNext)
+{
+ uint32_t idxNext;
+ if (pNext)
+ {
+ idxNext = (uint32_t)(pNext - &pQueueCC->paTimers[0]);
+ Assert(idxNext);
+ AssertMsgStmt(idxNext < pQueueCC->cTimersAlloc,
+ ("idxNext=%u (%s) cTimersAlloc=%u\n", idxNext, pNext->szName, pQueueCC->cTimersAlloc),
+ idxNext = UINT32_MAX);
+ }
+ else
+ idxNext = UINT32_MAX;
+ pTimer->idxNext = idxNext;
+}
+
+
+/**
+ * Used to unlink a timer from the active list.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pQueueCC The context specific queue data (same as @a pQueue for
+ * ring-3).
+ * @param pQueue The shared timer queue data.
+ * @param pTimer The timer that needs linking.
+ *
+ * @remarks Called while owning the relevant queue lock.
+ */
+DECL_FORCE_INLINE(void) tmTimerQueueUnlinkActive(PVMCC pVM, PTMTIMERQUEUECC pQueueCC, PTMTIMERQUEUE pQueue, PTMTIMER pTimer)
+{
+#ifdef VBOX_STRICT
+ TMTIMERSTATE const enmState = pTimer->enmState;
+ Assert( pQueue->enmClock == TMCLOCK_VIRTUAL_SYNC
+ ? enmState == TMTIMERSTATE_ACTIVE
+ : enmState == TMTIMERSTATE_PENDING_SCHEDULE || enmState == TMTIMERSTATE_PENDING_STOP_SCHEDULE);
+#endif
+ RT_NOREF(pVM);
+
+ const PTMTIMER pPrev = tmTimerGetPrev(pQueueCC, pTimer);
+ const PTMTIMER pNext = tmTimerGetNext(pQueueCC, pTimer);
+ if (pPrev)
+ tmTimerSetNext(pQueueCC, pPrev, pNext);
+ else
+ {
+ tmTimerQueueSetHead(pQueueCC, pQueue, pNext);
+ pQueue->u64Expire = pNext ? pNext->u64Expire : INT64_MAX;
+ DBGFTRACE_U64_TAG(pVM, pQueue->u64Expire, "tmTimerQueueUnlinkActive");
+ }
+ if (pNext)
+ tmTimerSetPrev(pQueueCC, pNext, pPrev);
+ pTimer->idxNext = UINT32_MAX;
+ pTimer->idxPrev = UINT32_MAX;
+}
+
+/** @def TMTIMER_HANDLE_TO_VARS_RETURN_EX
+ * Converts a timer handle to a timer pointer, returning @a a_rcRet if the
+ * handle is invalid.
+ *
+ * This defines the following variables:
+ * - idxQueue: The queue index.
+ * - pQueueCC: Pointer to the context specific queue data.
+ * - pTimer: The timer pointer.
+ * - idxTimer: The timer index.
+ *
+ * @param a_pVM The cross context VM structure.
+ * @param a_hTimer The timer handle to translate.
+ * @param a_rcRet What to return on failure.
+ *
+ * @note This macro has no scoping, so careful when using it around
+ * conditional statements!
+ */
+#ifdef IN_RING3
+# define TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, a_rcRet) \
+ uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
+ & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
+ AssertReturn(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues), a_rcRet); \
+ PTMTIMERQUEUE const pQueue = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; \
+ PTMTIMERQUEUE const pQueueCC = pQueue; RT_NOREF(pQueueCC); \
+ \
+ uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
+ AssertReturn(idxQueue < pQueue->cTimersAlloc, a_rcRet); \
+ \
+ PTMTIMER const pTimer = &pQueue->paTimers[idxTimer]; \
+ AssertReturn(pTimer->hSelf == a_hTimer, a_rcRet)
+#else
+# define TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, a_rcRet) \
+ uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
+ & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
+ AssertReturn(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues), a_rcRet); \
+ AssertCompile(RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues) == RT_ELEMENTS((a_pVM)->tmr0.s.aTimerQueues)); \
+ PTMTIMERQUEUE const pQueue = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; RT_NOREF(pQueue); \
+ PTMTIMERQUEUER0 const pQueueCC = &(a_pVM)->tmr0.s.aTimerQueues[idxQueue]; \
+ \
+ uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
+ AssertReturn(idxQueue < pQueueCC->cTimersAlloc, a_rcRet); \
+ \
+ PTMTIMER const pTimer = &pQueueCC->paTimers[idxTimer]; \
+ AssertReturn(pTimer->hSelf == a_hTimer, a_rcRet); \
+ Assert(pTimer->fFlags & TMTIMER_FLAGS_RING0); \
+ Assert(VM_IS_EMT(pVM))
+#endif
+
+/** @def TMTIMER_HANDLE_TO_VARS_RETURN
+ * Converts a timer handle to a timer pointer, returning VERR_INVALID_HANDLE if
+ * the handle is invalid.
+ *
+ * This defines the following variables:
+ * - idxQueue: The queue index.
+ * - pQueueCC: Pointer to the context specific queue data.
+ * - pTimer: The timer pointer.
+ * - idxTimer: The timer index.
+ *
+ * @param a_pVM The cross context VM structure.
+ * @param a_hTimer The timer handle to translate.
+ *
+ * @note This macro has no scoping, so careful when using it around
+ * conditional statements!
+ */
+#define TMTIMER_HANDLE_TO_VARS_RETURN(a_pVM, a_hTimer) TMTIMER_HANDLE_TO_VARS_RETURN_EX(a_pVM, a_hTimer, VERR_INVALID_HANDLE)
+
+/** @def TMTIMER_HANDLE_TO_VARS_RETURN_VOID
+ * Converts a timer handle to a timer pointer, returning void if the
+ * handle is invalid.
+ *
+ * This defines the following variables:
+ * - idxQueue: The queue index.
+ * - pQueueCC: Pointer to the context specific queue data.
+ * - pTimer: The timer pointer.
+ * - idxTimer: The timer index.
+ *
+ * @param a_pVM The cross context VM structure.
+ * @param a_hTimer The timer handle to translate.
+ *
+ * @note This macro has no scoping, so careful when using it around
+ * conditional statements!
+ */
+#ifdef IN_RING3
+# define TMTIMER_HANDLE_TO_VARS_RETURN_VOID(a_pVM, a_hTimer) \
+ uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
+ & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
+ AssertReturnVoid(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues)); \
+ PTMTIMERQUEUE const pQueue = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; \
+ PTMTIMERQUEUE const pQueueCC = pQueue; RT_NOREF(pQueueCC); \
+ \
+ uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
+ AssertReturnVoid(idxQueue < pQueue->cTimersAlloc); \
+ \
+ PTMTIMER const pTimer = &pQueue->paTimers[idxTimer]; \
+ AssertReturnVoid(pTimer->hSelf == a_hTimer)
+#else
+# define TMTIMER_HANDLE_TO_VARS_RETURN_VOID(a_pVM, a_hTimer) \
+ uintptr_t const idxQueue = (uintptr_t)((a_hTimer) >> TMTIMERHANDLE_QUEUE_IDX_SHIFT) \
+ & (uintptr_t)TMTIMERHANDLE_QUEUE_IDX_SMASK; \
+ AssertReturnVoid(idxQueue < RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues)); \
+ AssertCompile(RT_ELEMENTS((a_pVM)->tm.s.aTimerQueues) == RT_ELEMENTS((a_pVM)->tmr0.s.aTimerQueues)); \
+ PTMTIMERQUEUE const pQueue = &(a_pVM)->tm.s.aTimerQueues[idxQueue]; RT_NOREF(pQueue); \
+ PTMTIMERQUEUER0 const pQueueCC = &(a_pVM)->tmr0.s.aTimerQueues[idxQueue]; \
+ \
+ uintptr_t const idxTimer = (uintptr_t)((a_hTimer) & TMTIMERHANDLE_TIMER_IDX_MASK); \
+ AssertReturnVoid(idxQueue < pQueueCC->cTimersAlloc); \
+ \
+ PTMTIMER const pTimer = &pQueueCC->paTimers[idxTimer]; \
+ AssertReturnVoid(pTimer->hSelf == a_hTimer); \
+ Assert(pTimer->fFlags & TMTIMER_FLAGS_RING0); \
+ Assert(VM_IS_EMT(pVM))
+#endif
+
+#endif /* !VMM_INCLUDED_SRC_include_TMInline_h */
+