VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/TMR0.cpp

Last change on this file was 100208, checked in by vboxsync, 11 months ago

VMM/TMR0: Fix assertion, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.6 KB
Line 
1/* $Id: TMR0.cpp 100208 2023-06-19 14:28:17Z vboxsync $ */
2/** @file
3 * TM - Timeout Manager, host ring-0 context.
4 */
5
6/*
7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_TM
33#include <VBox/vmm/tm.h>
34#include "TMInternal.h"
35#include <VBox/vmm/gvm.h>
36
37#include <VBox/err.h>
38#include <VBox/log.h>
39#include <VBox/param.h>
40#include <iprt/assert.h>
41#include <iprt/mem.h>
42#include <iprt/memobj.h>
43#include <iprt/process.h>
44#include <iprt/string.h>
45
46
47
48/**
49 * Initializes the per-VM data for the TM.
50 *
51 * This is called from under the GVMM lock, so it should only initialize the
52 * data so TMR0CleanupVM and others will work smoothly.
53 *
54 * @param pGVM Pointer to the global VM structure.
55 */
56VMMR0_INT_DECL(void) TMR0InitPerVMData(PGVM pGVM)
57{
58 AssertCompile(sizeof(pGVM->tmr0.padding) >= sizeof(pGVM->tmr0.s));
59
60 for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues); idxQueue++)
61 {
62 pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj = NIL_RTR0MEMOBJ;
63 pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj = NIL_RTR0MEMOBJ;
64 }
65
66 pGVM->tmr0.s.VirtualGetRawData.pu64Prev = &pGVM->tm.s.u64VirtualRawPrev;
67 pGVM->tmr0.s.VirtualGetRawData.pfnBad = tmVirtualNanoTSBad;
68 pGVM->tmr0.s.VirtualGetRawData.pfnBadCpuIndex = tmVirtualNanoTSBadCpuIndex;
69 pGVM->tmr0.s.VirtualGetRawData.pfnRediscover = tmVirtualNanoTSRediscover;
70 pGVM->tmr0.s.pfnVirtualGetRaw = tmVirtualNanoTSRediscover;
71}
72
73
74/**
75 * Cleans up any loose ends before the GVM structure is destroyed.
76 */
77VMMR0_INT_DECL(void) TMR0CleanupVM(PGVM pGVM)
78{
79 for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues); idxQueue++)
80 {
81 if (pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj == NIL_RTR0MEMOBJ)
82 {
83 RTR0MemObjFree(pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj, true /*fFreeMappings*/);
84 pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj = NIL_RTR0MEMOBJ;
85 }
86
87 if (pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj != NIL_RTR0MEMOBJ)
88 {
89 RTR0MemObjFree(pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj, true /*fFreeMappings*/);
90 pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj = NIL_RTR0MEMOBJ;
91 }
92 }
93}
94
95
96/**
97 * Grows the timer array for @a idxQueue to at least @a cMinTimers entries.
98 *
99 * @returns VBox status code.
100 * @param pGVM The ring-0 VM structure.
101 * @param idxQueue The index of the queue to grow.
102 * @param cMinTimers The minimum growth target.
103 * @thread EMT
104 * @note Caller must own the queue lock exclusively.
105 */
106VMMR0_INT_DECL(int) TMR0TimerQueueGrow(PGVM pGVM, uint32_t idxQueue, uint32_t cMinTimers)
107{
108 /*
109 * Validate input and state.
110 */
111 VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
112 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE); /** @todo must do better than this! */
113 AssertReturn(idxQueue < RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues), VERR_TM_INVALID_TIMER_QUEUE);
114 AssertCompile(RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues) == RT_ELEMENTS(pGVM->tm.s.aTimerQueues));
115 PTMTIMERQUEUER0 pQueueR0 = &pGVM->tmr0.s.aTimerQueues[idxQueue];
116 PTMTIMERQUEUE pQueueShared = &pGVM->tm.s.aTimerQueues[idxQueue];
117 AssertMsgReturn(PDMCritSectRwIsWriteOwner(pGVM, &pQueueShared->AllocLock),
118 ("queue=%s %.*Rhxs\n", pQueueShared->szName, sizeof(pQueueShared->AllocLock), &pQueueShared->AllocLock),
119 VERR_NOT_OWNER);
120
121 uint32_t cNewTimers = cMinTimers;
122 AssertReturn(cNewTimers <= _32K, VERR_TM_TOO_MANY_TIMERS);
123 uint32_t const cOldTimers = pQueueR0->cTimersAlloc;
124 ASMCompilerBarrier();
125 AssertReturn(cNewTimers >= cOldTimers, VERR_TM_IPE_1);
126 AssertReturn(cOldTimers == pQueueShared->cTimersAlloc, VERR_TM_IPE_2);
127
128 /*
129 * Round up the request to the nearest page and do the allocation.
130 */
131 size_t cbNew = sizeof(TMTIMER) * cNewTimers;
132 cbNew = RT_ALIGN_Z(cbNew, HOST_PAGE_SIZE);
133 cNewTimers = (uint32_t)(cbNew / sizeof(TMTIMER));
134
135 RTR0MEMOBJ hMemObj;
136 int rc = RTR0MemObjAllocPage(&hMemObj, cbNew, false /*fExecutable*/);
137 if (RT_SUCCESS(rc))
138 {
139 /*
140 * Zero and map it.
141 */
142 PTMTIMER paTimers = (PTMTIMER)RTR0MemObjAddress(hMemObj);
143 RT_BZERO(paTimers, cbNew);
144
145 RTR0MEMOBJ hMapObj;
146 rc = RTR0MemObjMapUser(&hMapObj, hMemObj, (RTR3PTR)-1, HOST_PAGE_SIZE,
147 RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf());
148 if (RT_SUCCESS(rc))
149 {
150 tmHCTimerQueueGrowInit(paTimers, pQueueR0->paTimers, cNewTimers, cOldTimers);
151
152 /*
153 * Switch the memory handles.
154 */
155 RTR0MEMOBJ hTmp = pQueueR0->hMapObj;
156 pQueueR0->hMapObj = hMapObj;
157 hMapObj = hTmp;
158
159 hTmp = pQueueR0->hMemObj;
160 pQueueR0->hMemObj = hMemObj;
161 hMemObj = hTmp;
162
163 /*
164 * Update the variables.
165 */
166 pQueueR0->paTimers = paTimers;
167 pQueueR0->cTimersAlloc = cNewTimers;
168 pQueueShared->paTimers = RTR0MemObjAddressR3(pQueueR0->hMapObj);
169 pQueueShared->cTimersAlloc = cNewTimers;
170 pQueueShared->cTimersFree += cNewTimers - (cOldTimers ? cOldTimers : 1);
171
172 /*
173 * Free the old allocation.
174 */
175 RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
176 }
177 RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
178 }
179
180 return rc;
181}
182
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use