VirtualBox

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

Last change on this file since 92489 was 90347, checked in by vboxsync, 3 years ago

VMM: Pass pVM to PDMCritSectRw APIs. bugref:9218 bugref:10074

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette