VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.9 KB
Line 
1/* $Id: PDMR0Queue.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * PDM Queue - Transport data and tasks to EMT and R3, ring-0 code.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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_PDM_QUEUE
33#include "PDMInternal.h"
34#include <VBox/vmm/pdm.h>
35#include <VBox/vmm/vmcc.h>
36#include <VBox/log.h>
37#include <iprt/errcore.h>
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/mem.h>
41#include <iprt/memobj.h>
42#include <iprt/process.h>
43#include <iprt/string.h>
44
45
46
47/**
48 * Creates a ring-0 capable queue.
49 *
50 * This is only callable from EMT(0) when the VM is the VMSTATE_CREATING state.
51 *
52 * @returns VBox status code.
53 * @param pGVM The ring-0 VM structure.
54 * @param pReq The queue create request.
55 * @thread EMT(0)
56 */
57VMMR0_INT_DECL(int) PDMR0QueueCreateReqHandler(PGVM pGVM, PPDMQUEUECREATEREQ pReq)
58{
59 /*
60 * Validate input.
61 * Note! Restricting to EMT(0) to avoid locking requirements.
62 */
63 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0 /*idCpu*/);
64 AssertRCReturn(rc, rc);
65
66 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
67
68 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
69 AssertReturn(pReq->cItems <= PDMQUEUE_MAX_ITEMS, VERR_OUT_OF_RANGE);
70 AssertReturn(pReq->cItems > 0, VERR_INVALID_PARAMETER);
71 AssertReturn(pReq->cbItem <= PDMQUEUE_MAX_ITEM_SIZE, VERR_OUT_OF_RANGE);
72 AssertReturn(pReq->cbItem >= sizeof(PDMQUEUEITEMCORE), VERR_INVALID_PARAMETER);
73 pReq->cbItem = RT_ALIGN_32(pReq->cbItem, sizeof(uint64_t));
74 AssertReturn((uint64_t)pReq->cbItem * pReq->cItems <= PDMQUEUE_MAX_TOTAL_SIZE_R0, VERR_OUT_OF_RANGE);
75
76 void *pvOwnerR0;
77 switch ((PDMQUEUETYPE)pReq->enmType)
78 {
79 case PDMQUEUETYPE_DEV:
80 {
81 AssertReturn(pReq->pvOwner != NIL_RTR3PTR, VERR_INVALID_POINTER);
82 AssertReturn(!(pReq->pvOwner & HOST_PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
83
84 pvOwnerR0 = NULL;
85 uint32_t i = pGVM->pdmr0.s.cDevInstances;
86 while (i-- > 0)
87 {
88 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[i];
89 if ( pDevIns
90 && RTR0MemObjAddressR3(pDevIns->Internal.s.hMapObj) == pReq->pvOwner)
91 {
92 pvOwnerR0 = pDevIns;
93 break;
94 }
95 }
96 AssertReturn(pvOwnerR0, VERR_NOT_OWNER);
97 break;
98 }
99
100 case PDMQUEUETYPE_INTERNAL:
101 AssertReturn(pReq->pvOwner == pGVM->pVMR3, VERR_NOT_OWNER);
102 pvOwnerR0 = pGVM;
103 break;
104
105 default:
106 AssertFailedReturn(VERR_INVALID_FUNCTION);
107 }
108
109 AssertReturn(pGVM->pdmr0.s.cQueues < RT_ELEMENTS(pGVM->pdmr0.s.aQueues), VERR_OUT_OF_RESOURCES);
110
111 /*
112 * Calculate the memory needed and allocate it.
113 */
114 uint32_t const cbBitmap = RT_ALIGN_32(RT_ALIGN_32(pReq->cItems, 64 /*uint64_t*/) / 8, 64 /*cache line */);
115 uint32_t const cbQueue = RT_UOFFSETOF(PDMQUEUE, bmAlloc)
116 + cbBitmap
117 + pReq->cbItem * pReq->cItems;
118
119 RTR0MEMOBJ hMemObj = NIL_RTR0MEMOBJ;
120 rc = RTR0MemObjAllocPage(&hMemObj, cbQueue, false /*fExecutable*/);
121 if (RT_SUCCESS(rc))
122 {
123 PPDMQUEUE pQueue = (PPDMQUEUE)RTR0MemObjAddress(hMemObj);
124
125 /*
126 * Initialize the queue.
127 */
128 pdmQueueInit(pQueue, cbBitmap, pReq->cbItem, pReq->cItems, pReq->szName,
129 (PDMQUEUETYPE)pReq->enmType, pReq->pfnCallback, pReq->pvOwner);
130
131 /*
132 * Map it into ring-3.
133 */
134 RTR0MEMOBJ hMapObj = NIL_RTR0MEMOBJ;
135 rc = RTR0MemObjMapUser(&hMapObj, hMemObj, (RTR3PTR)-1, HOST_PAGE_SIZE,
136 RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf());
137 if (RT_SUCCESS(rc))
138 {
139 /*
140 * Enter it into the handle tables.
141 */
142 uint32_t iQueue = pGVM->pdmr0.s.cQueues;
143 if (iQueue < RT_ELEMENTS(pGVM->pdmr0.s.aQueues))
144 {
145 pGVM->pdmr0.s.aQueues[iQueue].pQueue = pQueue;
146 pGVM->pdmr0.s.aQueues[iQueue].hMemObj = hMemObj;
147 pGVM->pdmr0.s.aQueues[iQueue].hMapObj = hMapObj;
148 pGVM->pdmr0.s.aQueues[iQueue].pvOwner = pvOwnerR0;
149 pGVM->pdmr0.s.aQueues[iQueue].cbItem = pReq->cbItem;
150 pGVM->pdmr0.s.aQueues[iQueue].cItems = pReq->cItems;
151 pGVM->pdmr0.s.aQueues[iQueue].u32Reserved = UINT32_C(0xf00dface);
152
153 pGVM->pdm.s.apRing0Queues[iQueue] = RTR0MemObjAddressR3(hMapObj);
154
155 ASMCompilerBarrier(); /* paranoia */
156 pGVM->pdm.s.cRing0Queues = iQueue + 1;
157 pGVM->pdmr0.s.cQueues = iQueue + 1;
158
159 pReq->hQueue = iQueue;
160 return VINF_SUCCESS;
161
162 }
163 rc = VERR_OUT_OF_RESOURCES;
164
165 RTR0MemObjFree(hMapObj, true /*fFreeMappings*/);
166 }
167 RTR0MemObjFree(hMemObj, true /*fFreeMappings*/);
168 }
169 return rc;
170}
171
172
173/**
174 * Called by PDMR0CleanupVM to clean up a queue.
175 *
176 * @param pGVM The ring-0 VM structure.
177 * @param iQueue Index into the ring-0 queue table.
178 */
179DECLHIDDEN(void) pdmR0QueueDestroy(PGVM pGVM, uint32_t iQueue)
180{
181 AssertReturnVoid(iQueue < RT_ELEMENTS(pGVM->pdmr0.s.aQueues));
182
183 PPDMQUEUE pQueue = pGVM->pdmr0.s.aQueues[iQueue].pQueue;
184 pGVM->pdmr0.s.aQueues[iQueue].pQueue = NULL;
185 if (RT_VALID_PTR(pQueue))
186 pQueue->u32Magic = PDMQUEUE_MAGIC_DEAD;
187
188 pGVM->pdmr0.s.aQueues[iQueue].pvOwner = NULL;
189
190 RTR0MemObjFree(pGVM->pdmr0.s.aQueues[iQueue].hMapObj, true /*fFreeMappings*/);
191 pGVM->pdmr0.s.aQueues[iQueue].hMapObj = NIL_RTR0MEMOBJ;
192
193 RTR0MemObjFree(pGVM->pdmr0.s.aQueues[iQueue].hMemObj, true /*fFreeMappings*/);
194 pGVM->pdmr0.s.aQueues[iQueue].hMemObj = NIL_RTR0MEMOBJ;
195}
196
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