VirtualBox

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

Last change on this file since 94771 was 93655, checked in by vboxsync, 3 years ago

VMM/TM,VMM/*: Moved RTTIMENANOTSDATAR0 into the ring-0 only part of the VM structure. Added a VMCC_CTX macro for selecting between tm and tmr0 VM components depending on the compilation context. Added a bunch of missing padding checks for GVM. bugref:10094

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.3 KB
Line 
1/* $Id: TMR0.cpp 93655 2022-02-08 13:56:01Z vboxsync $ */
2/** @file
3 * TM - Timeout Manager, host ring-0 context.
4 */
5
6/*
7 * Copyright (C) 2021-2022 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 AssertCompile(sizeof(pGVM->tmr0.padding) >= sizeof(pGVM->tmr0.s));
49
50 for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues); idxQueue++)
51 {
52 pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj = NIL_RTR0MEMOBJ;
53 pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj = NIL_RTR0MEMOBJ;
54 }
55
56 pGVM->tmr0.s.VirtualGetRawData.pu64Prev = &pGVM->tm.s.u64VirtualRawPrev;
57 pGVM->tmr0.s.VirtualGetRawData.pfnBad = tmVirtualNanoTSBad;
58 pGVM->tmr0.s.VirtualGetRawData.pfnBadCpuIndex = tmVirtualNanoTSBadCpuIndex;
59 pGVM->tmr0.s.VirtualGetRawData.pfnRediscover = tmVirtualNanoTSRediscover;
60 pGVM->tmr0.s.pfnVirtualGetRaw = tmVirtualNanoTSRediscover;
61}
62
63
64/**
65 * Cleans up any loose ends before the GVM structure is destroyed.
66 */
67VMMR0_INT_DECL(void) TMR0CleanupVM(PGVM pGVM)
68{
69 for (uint32_t idxQueue = 0; idxQueue < RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues); idxQueue++)
70 {
71 if (pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj == NIL_RTR0MEMOBJ)
72 {
73 RTR0MemObjFree(pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj, true /*fFreeMappings*/);
74 pGVM->tmr0.s.aTimerQueues[idxQueue].hMapObj = NIL_RTR0MEMOBJ;
75 }
76
77 if (pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj != NIL_RTR0MEMOBJ)
78 {
79 RTR0MemObjFree(pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj, true /*fFreeMappings*/);
80 pGVM->tmr0.s.aTimerQueues[idxQueue].hMemObj = NIL_RTR0MEMOBJ;
81 }
82 }
83}
84
85
86/**
87 * Grows the timer array for @a idxQueue to at least @a cMinTimers entries.
88 *
89 * @returns VBox status code.
90 * @param pGVM The ring-0 VM structure.
91 * @param idxQueue The index of the queue to grow.
92 * @param cMinTimers The minimum growth target.
93 * @thread EMT
94 * @note Caller must own the queue lock exclusively.
95 */
96VMMR0_INT_DECL(int) TMR0TimerQueueGrow(PGVM pGVM, uint32_t idxQueue, uint32_t cMinTimers)
97{
98 /*
99 * Validate input and state.
100 */
101 VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
102 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE); /** @todo must do better than this! */
103 AssertReturn(idxQueue <= RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues), VERR_TM_INVALID_TIMER_QUEUE);
104 AssertCompile(RT_ELEMENTS(pGVM->tmr0.s.aTimerQueues) == RT_ELEMENTS(pGVM->tm.s.aTimerQueues));
105 PTMTIMERQUEUER0 pQueueR0 = &pGVM->tmr0.s.aTimerQueues[idxQueue];
106 PTMTIMERQUEUE pQueueShared = &pGVM->tm.s.aTimerQueues[idxQueue];
107 AssertMsgReturn(PDMCritSectRwIsWriteOwner(pGVM, &pQueueShared->AllocLock),
108 ("queue=%s %.*Rhxs\n", pQueueShared->szName, sizeof(pQueueShared->AllocLock), &pQueueShared->AllocLock),
109 VERR_NOT_OWNER);
110
111 uint32_t cNewTimers = cMinTimers;
112 AssertReturn(cNewTimers <= _32K, VERR_TM_TOO_MANY_TIMERS);
113 uint32_t const cOldTimers = pQueueR0->cTimersAlloc;
114 ASMCompilerBarrier();
115 AssertReturn(cNewTimers >= cOldTimers, VERR_TM_IPE_1);
116 AssertReturn(cOldTimers == pQueueShared->cTimersAlloc, VERR_TM_IPE_2);
117
118 /*
119 * Round up the request to the nearest page and do the allocation.
120 */
121 size_t cbNew = sizeof(TMTIMER) * cNewTimers;
122 cbNew = RT_ALIGN_Z(cbNew, HOST_PAGE_SIZE);
123 cNewTimers = (uint32_t)(cbNew / sizeof(TMTIMER));
124
125 RTR0MEMOBJ hMemObj;
126 int rc = RTR0MemObjAllocPage(&hMemObj, cbNew, false /*fExecutable*/);
127 if (RT_SUCCESS(rc))
128 {
129 /*
130 * Zero and map it.
131 */
132 PTMTIMER paTimers = (PTMTIMER)RTR0MemObjAddress(hMemObj);
133 RT_BZERO(paTimers, cbNew);
134
135 RTR0MEMOBJ hMapObj;
136 rc = RTR0MemObjMapUser(&hMapObj, hMemObj, (RTR3PTR)-1, HOST_PAGE_SIZE,
137 RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf());
138 if (RT_SUCCESS(rc))
139 {
140 tmHCTimerQueueGrowInit(paTimers, pQueueR0->paTimers, cNewTimers, cOldTimers);
141
142 /*
143 * Switch the memory handles.
144 */
145 RTR0MEMOBJ hTmp = pQueueR0->hMapObj;
146 pQueueR0->hMapObj = hMapObj;
147 hMapObj = hTmp;
148
149 hTmp = pQueueR0->hMemObj;
150 pQueueR0->hMemObj = hMemObj;
151 hMemObj = hTmp;
152
153 /*
154 * Update the variables.
155 */
156 pQueueR0->paTimers = paTimers;
157 pQueueR0->cTimersAlloc = cNewTimers;
158 pQueueShared->paTimers = RTR0MemObjAddressR3(pQueueR0->hMapObj);
159 pQueueShared->cTimersAlloc = cNewTimers;
160 pQueueShared->cTimersFree += cNewTimers - (cOldTimers ? cOldTimers : 1);
161
162 /*
163 * Free the old allocation.
164 */
165 RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
166 }
167 RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
168 }
169
170 return rc;
171}
172
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