VirtualBox

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

最後變更 在這個檔案從93102是 92712,由 vboxsync 提交於 3 年 前

VMM/TM: Made timer allocation work in driverless mode. bugref:10138

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 5.8 KB
 
1/* $Id: TMR0.cpp 92712 2021-12-02 17:34:24Z 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.alldomusa.eu.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 cOldTimers = pQueueR0->cTimersAlloc;
106 ASMCompilerBarrier();
107 AssertReturn(cNewTimers >= cOldTimers, VERR_TM_IPE_1);
108 AssertReturn(cOldTimers == 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 tmHCTimerQueueGrowInit(paTimers, pQueueR0->paTimers, cNewTimers, cOldTimers);
132
133 /*
134 * Switch the memory handles.
135 */
136 RTR0MEMOBJ hTmp = pQueueR0->hMapObj;
137 pQueueR0->hMapObj = hMapObj;
138 hMapObj = hTmp;
139
140 hTmp = pQueueR0->hMemObj;
141 pQueueR0->hMemObj = hMemObj;
142 hMemObj = hTmp;
143
144 /*
145 * Update the variables.
146 */
147 pQueueR0->paTimers = paTimers;
148 pQueueR0->cTimersAlloc = cNewTimers;
149 pQueueShared->paTimers = RTR0MemObjAddressR3(pQueueR0->hMapObj);
150 pQueueShared->cTimersAlloc = cNewTimers;
151 pQueueShared->cTimersFree += cNewTimers - (cOldTimers ? cOldTimers : 1);
152
153 /*
154 * Free the old allocation.
155 */
156 RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
157 }
158 RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
159 }
160
161 return rc;
162}
163
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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