VirtualBox

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

Last change on this file since 94800 was 93610, checked in by vboxsync, 3 years ago

VMM/PDMQueue: Rewrote the queue code to not use the hyper heap and be a bit safer. Added a testcase (driverless). [missing file] bugref:10093

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