VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp@ 9609

Last change on this file since 9609 was 9609, checked in by vboxsync, 17 years ago

Todo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.6 KB
Line 
1/* $Id: mp-r0drv-nt.cpp 9609 2008-06-11 13:05:24Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Ring-0 Driver, NT.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "the-nt-kernel.h"
36
37#include <iprt/mp.h>
38#include <iprt/cpuset.h>
39#include <iprt/err.h>
40#include <iprt/asm.h>
41#include "r0drv/mp-r0drv.h"
42#include "internal-r0drv-nt.h"
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48typedef enum
49{
50 RT_NT_CPUID_SPECIFIC,
51 RT_NT_CPUID_OTHERS,
52 RT_NT_CPUID_ALL
53} RT_NT_CPUID;
54
55
56/* test a couple of assumption. */
57AssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS);
58AssertCompile(NIL_RTCPUID >= MAXIMUM_PROCESSORS);
59
60/** @todo
61 * We cannot do other than assume a 1:1 relationship between the
62 * affinity mask and the process despite the vagueness/warnings in
63 * the docs. If someone knows a better way to get this done, please
64 * let bird know.
65 */
66
67
68RTDECL(RTCPUID) RTMpCpuId(void)
69{
70 /* WDK upgrade warning: PCR->Number changed from BYTE to WORD. */
71 return KeGetCurrentProcessorNumber();
72}
73
74
75RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
76{
77 return idCpu < MAXIMUM_PROCESSORS ? (int)idCpu : -1;
78}
79
80
81RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
82{
83 return (unsigned)iCpu < MAXIMUM_PROCESSORS ? iCpu : NIL_RTCPUID;
84}
85
86
87RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
88{
89 return MAXIMUM_PROCESSORS - 1;
90}
91
92
93RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
94{
95 if (idCpu >= MAXIMUM_PROCESSORS)
96 return false;
97
98#if 0 /* this isn't safe at all IRQLs (great work guys) */
99 KAFFINITY Mask = KeQueryActiveProcessors();
100 return !!(Mask & RT_BIT_64(idCpu));
101#else
102 return RTCpuSetIsMember(&g_rtMpNtCpuSet, idCpu);
103#endif
104}
105
106
107RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
108{
109 /* Cannot easily distinguish between online and offline cpus. */
110 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
111 return RTMpIsCpuOnline(idCpu);
112}
113
114
115RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
116{
117 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
118 return RTMpGetOnlineSet(pSet);
119}
120
121
122RTDECL(RTCPUID) RTMpGetCount(void)
123{
124 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
125 return RTMpGetOnlineCount();
126}
127
128
129RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
130{
131#if 0 /* this isn't safe at all IRQLs (great work guys) */
132 KAFFINITY Mask = KeQueryActiveProcessors();
133 return RTCpuSetFromU64(pSet, Mask);
134#else
135 *pSet = g_rtMpNtCpuSet;
136 return pSet;
137#endif
138}
139
140
141RTDECL(RTCPUID) RTMpGetOnlineCount(void)
142{
143 RTCPUSET Set;
144 RTMpGetOnlineSet(&Set);
145 return RTCpuSetCount(&Set);
146}
147
148
149/**
150 * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
151 *
152 * @param Dpc DPC object
153 * @param DeferredContext Context argument specified by KeInitializeDpc
154 * @param SystemArgument1 Argument specified by KeInsertQueueDpc
155 * @param SystemArgument2 Argument specified by KeInsertQueueDpc
156 */
157static VOID rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
158{
159 PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
160 ASMAtomicIncU32(&pArgs->cHits);
161 pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
162}
163
164
165/**
166 * Internal worker for the RTMpOn* APIs.
167 *
168 * @returns IPRT status code.
169 * @param pfnWorker The callback.
170 * @param pvUser1 User argument 1.
171 * @param pvUser2 User argument 2.
172 * @param enmCpuid What to do / is idCpu valid.
173 * @param idCpu Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
174 */
175static int rtMpCall(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
176{
177 PRTMPARGS pArgs;
178 KDPC *paExecCpuDpcs;
179
180#if 0
181 /* KeFlushQueuedDpcs must be run at IRQL PASSIVE_LEVEL according to MSDN, but the
182 * driver verifier doesn't complain...
183 */
184 AssertMsg(KeGetCurrentIrql() == PASSIVE_LEVEL, ("%d != %d (PASSIVE_LEVEL)\n", KeGetCurrentIrql(), PASSIVE_LEVEL));
185#endif
186
187 KAFFINITY Mask = KeQueryActiveProcessors();
188
189 /* KeFlushQueuedDpcs is not present in Windows 2000; import it dynamically so we can just fail this call. */
190 if (!g_pfnrtNtKeFlushQueuedDpcs)
191 return VERR_NOT_SUPPORTED;
192
193 pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_PROCESSORS*sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp');
194 if (!pArgs)
195 return VERR_NO_MEMORY;
196
197 pArgs->pfnWorker = pfnWorker;
198 pArgs->pvUser1 = pvUser1;
199 pArgs->pvUser2 = pvUser2;
200 pArgs->idCpu = NIL_RTCPUID;
201 pArgs->cHits = 0;
202
203 paExecCpuDpcs = (KDPC *)(pArgs + 1);
204
205 if (enmCpuid == RT_NT_CPUID_SPECIFIC)
206 {
207 KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs);
208 KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
209 KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu);
210 }
211 else
212 {
213 for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
214 {
215 KeInitializeDpc(&paExecCpuDpcs[i], rtmpNtDPCWrapper, pArgs);
216 KeSetImportanceDpc(&paExecCpuDpcs[i], HighImportance);
217 KeSetTargetProcessorDpc(&paExecCpuDpcs[i], i);
218 }
219 }
220
221 /* Raise the IRQL to DISPATCH_LEVEL so we can't be rescheduled to another cpu.
222 * KeInsertQueueDpc must also be executed at IRQL >= DISPATCH_LEVEL.
223 */
224 KIRQL oldIrql;
225 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
226
227 /*
228 * We cannot do other than assume a 1:1 relationship between the
229 * affinity mask and the process despite the warnings in the docs.
230 * If someone knows a better way to get this done, please let bird know.
231 */
232 if (enmCpuid == RT_NT_CPUID_SPECIFIC)
233 {
234 BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0);
235 Assert(ret);
236 }
237 else
238 {
239 unsigned iSelf = KeGetCurrentProcessorNumber();
240
241 for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
242 {
243 if ( (i != iSelf)
244 && (Mask & RT_BIT_64(i)))
245 {
246 BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[i], 0, 0);
247 Assert(ret);
248 }
249 }
250 if (enmCpuid != RT_NT_CPUID_OTHERS)
251 pfnWorker(iSelf, pvUser1, pvUser2);
252 }
253
254 KeLowerIrql(oldIrql);
255
256 /* Flush all DPCs and wait for completion. (can take long!) */
257 /** @todo Consider changing this to an active wait using some atomic inc/dec
258 * stuff (and check for the current cpu above in the specific case). */
259 g_pfnrtNtKeFlushQueuedDpcs();
260
261 ExFreePool(pArgs);
262 return VINF_SUCCESS;
263}
264
265
266RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
267{
268 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
269}
270
271
272RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
273{
274 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
275}
276
277
278RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
279{
280 if (!RTMpIsCpuOnline(idCpu))
281 return !RTMpIsCpuPossible(idCpu)
282 ? VERR_CPU_NOT_FOUND
283 : VERR_CPU_OFFLINE;
284
285 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
286}
287
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