1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
/* $Id: PDMAllQueue.cpp $ */
/** @file
* PDM Queue - Transport data and tasks to EMT and R3.
*/
/*
* Copyright (C) 2006-2019 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*********************************************************************************************************************************
* Header Files *
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_PDM_QUEUE
#include "PDMInternal.h"
#include <VBox/vmm/pdm.h>
#ifndef IN_RC
# ifdef VBOX_WITH_REM
# include <VBox/vmm/rem.h>
# endif
# include <VBox/vmm/mm.h>
#endif
#include <VBox/vmm/vm.h>
#include <iprt/errcore.h>
#include <VBox/log.h>
#include <iprt/asm.h>
#include <iprt/assert.h>
/**
* Allocate an item from a queue.
* The allocated item must be handed on to PDMR3QueueInsert() after the
* data have been filled in.
*
* @returns Pointer to allocated queue item.
* @returns NULL on failure. The queue is exhausted.
* @param pQueue The queue handle.
* @thread Any thread.
*/
VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PPDMQUEUE pQueue)
{
Assert(VALID_PTR(pQueue) && pQueue->CTX_SUFF(pVM));
PPDMQUEUEITEMCORE pNew;
uint32_t iNext;
uint32_t i;
do
{
i = pQueue->iFreeTail;
if (i == pQueue->iFreeHead)
{
STAM_REL_COUNTER_INC(&pQueue->StatAllocFailures);
return NULL;
}
pNew = pQueue->aFreeItems[i].CTX_SUFF(pItem);
iNext = (i + 1) % (pQueue->cItems + PDMQUEUE_FREE_SLACK);
} while (!ASMAtomicCmpXchgU32(&pQueue->iFreeTail, iNext, i));
return pNew;
}
/**
* Sets the FFs and fQueueFlushed.
*
* @param pQueue The PDM queue.
*/
static void pdmQueueSetFF(PPDMQUEUE pQueue)
{
PVM pVM = pQueue->CTX_SUFF(pVM);
Log2(("PDMQueueInsert: VM_FF_PDM_QUEUES %d -> 1\n", VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES)));
VM_FF_SET(pVM, VM_FF_PDM_QUEUES);
ASMAtomicBitSet(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT);
#ifdef IN_RING3
# ifdef VBOX_WITH_REM
REMR3NotifyQueuePending(pVM); /** @todo r=bird: we can remove REMR3NotifyQueuePending and let VMR3NotifyFF do the work. */
# endif
VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_DONE_REM);
#endif
}
/**
* Queue an item.
* The item must have been obtained using PDMQueueAlloc(). Once the item
* have been passed to this function it must not be touched!
*
* @param pQueue The queue handle.
* @param pItem The item to insert.
* @thread Any thread.
*/
VMMDECL(void) PDMQueueInsert(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem)
{
Assert(VALID_PTR(pQueue) && pQueue->CTX_SUFF(pVM));
Assert(VALID_PTR(pItem));
#if 0 /* the paranoid android version: */
void *pvNext;
do
{
pvNext = ASMAtomicUoReadPtr((void * volatile *)&pQueue->CTX_SUFF(pPending));
ASMAtomicUoWritePtr((void * volatile *)&pItem->CTX_SUFF(pNext), pvNext);
} while (!ASMAtomicCmpXchgPtr(&pQueue->CTX_SUFF(pPending), pItem, pvNext));
#else
PPDMQUEUEITEMCORE pNext;
do
{
pNext = pQueue->CTX_SUFF(pPending);
pItem->CTX_SUFF(pNext) = pNext;
} while (!ASMAtomicCmpXchgPtr(&pQueue->CTX_SUFF(pPending), pItem, pNext));
#endif
if (!pQueue->pTimer)
pdmQueueSetFF(pQueue);
STAM_REL_COUNTER_INC(&pQueue->StatInsert);
STAM_STATS({ ASMAtomicIncU32(&pQueue->cStatPending); });
}
/**
* Queue an item.
* The item must have been obtained using PDMQueueAlloc(). Once the item
* have been passed to this function it must not be touched!
*
* @param pQueue The queue handle.
* @param pItem The item to insert.
* @param NanoMaxDelay The maximum delay before processing the queue, in nanoseconds.
* This applies only to GC.
* @thread Any thread.
*/
VMMDECL(void) PDMQueueInsertEx(PPDMQUEUE pQueue, PPDMQUEUEITEMCORE pItem, uint64_t NanoMaxDelay)
{
NOREF(NanoMaxDelay);
PDMQueueInsert(pQueue, pItem);
#ifdef IN_RC
PVM pVM = pQueue->CTX_SUFF(pVM);
/** @todo figure out where to put this, the next bit should go there too.
if (NanoMaxDelay)
{
}
else */
{
VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_TO_R3);
Log2(("PDMQueueInsertEx: Setting VMCPU_FF_TO_R3\n"));
}
#endif
}
/**
* Gets the RC pointer for the specified queue.
*
* @returns The RC address of the queue.
* @returns NULL if pQueue is invalid.
* @param pQueue The queue handle.
*/
VMMDECL(RCPTRTYPE(PPDMQUEUE)) PDMQueueRCPtr(PPDMQUEUE pQueue)
{
Assert(VALID_PTR(pQueue));
Assert(pQueue->pVMR3 && pQueue->pVMRC);
#ifdef IN_RC
return pQueue;
#else
return MMHyperCCToRC(pQueue->CTX_SUFF(pVM), pQueue);
#endif
}
/**
* Gets the ring-0 pointer for the specified queue.
*
* @returns The ring-0 address of the queue.
* @returns NULL if pQueue is invalid.
* @param pQueue The queue handle.
*/
VMMDECL(R0PTRTYPE(PPDMQUEUE)) PDMQueueR0Ptr(PPDMQUEUE pQueue)
{
Assert(VALID_PTR(pQueue));
Assert(pQueue->pVMR3 && pQueue->pVMR0);
#ifdef IN_RING0
return pQueue;
#else
return MMHyperCCToR0(pQueue->CTX_SUFF(pVM), pQueue);
#endif
}
/**
* Schedule the queue for flushing (processing) if necessary.
*
* @returns @c true if necessary, @c false if not.
* @param pQueue The queue.
*/
VMMDECL(bool) PDMQueueFlushIfNecessary(PPDMQUEUE pQueue)
{
AssertPtr(pQueue);
if ( pQueue->pPendingR3 != NIL_RTR3PTR
|| pQueue->pPendingR0 != NIL_RTR0PTR
|| pQueue->pPendingRC != NIL_RTRCPTR)
{
pdmQueueSetFF(pQueue);
return false;
}
return false;
}
|