VirtualBox

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

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

RTMpDoesCpuExist -> RTMpIsCpuPossible. Changed the RTMpGetCount and RTMpGetSet specification to include all possible cpus.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
Line 
1/* $Id: mp-r0drv-nt.cpp 9429 2008-06-05 15:22:37Z 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
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47typedef enum
48{
49 RT_NT_CPUID_SPECIFIC,
50 RT_NT_CPUID_OTHERS,
51 RT_NT_CPUID_ALL
52} RT_NT_CPUID;
53
54
55/* test a couple of assumption. */
56AssertCompile(MAXIMUM_PROCESSORS <= RTCPUSET_MAX_CPUS);
57AssertCompile(NIL_RTCPUID >= MAXIMUM_PROCESSORS);
58
59/** @todo
60 * We cannot do other than assume a 1:1 relationship between the
61 * affinity mask and the process despite the vagueness/warnings in
62 * the docs. If someone knows a better way to get this done, please
63 * let bird know.
64 */
65
66
67RTDECL(RTCPUID) RTMpCpuId(void)
68{
69 /* WDK upgrade warning: PCR->Number changed from BYTE to WORD. */
70 return KeGetCurrentProcessorNumber();
71}
72
73
74RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
75{
76 return idCpu < MAXIMUM_PROCESSORS ? idCpu : -1;
77}
78
79
80RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
81{
82 return (unsigned)iCpu < MAXIMUM_PROCESSORS ? iCpu : NIL_RTCPUID;
83}
84
85
86RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
87{
88 return MAXIMUM_PROCESSORS - 1;
89}
90
91
92RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
93{
94 if (idCpu >= MAXIMUM_PROCESSORS)
95 return false;
96
97 /** @todo this must be done at init time as it's not safe under all circumstances (braindead OS design). */
98 KAFFINITY Mask = KeQueryActiveProcessors();
99 return !!(Mask & RT_BIT_64(idCpu));
100}
101
102
103RTDECL(bool) RTMpIsCpuPresent(RTCPUID idCpu)
104{
105 /* Cannot easily distinguish between online and offline cpus. */
106 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
107 return RTMpIsCpuOnline(idCpu);
108}
109
110
111RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
112{
113 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
114 return RTMpGetOnlineSet(pSet);
115}
116
117
118RTDECL(RTCPUID) RTMpGetCount(void)
119{
120 /** @todo online/present cpu stuff must be corrected for proper W2K8 support. */
121 return RTMpGetOnlineCount();
122}
123
124
125RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
126{
127 KAFFINITY Mask = KeQueryActiveProcessors();
128 return RTCpuSetFromU64(pSet, Mask);
129}
130
131
132RTDECL(RTCPUID) RTMpGetOnlineCount(void)
133{
134 RTCPUSET Set;
135 RTMpGetOnlineSet(&Set);
136 return RTCpuSetCount(&Set);
137}
138
139
140/**
141 * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
142 *
143 * @param Dpc DPC object
144 * @param DeferredContext Context argument specified by KeInitializeDpc
145 * @param SystemArgument1 Argument specified by KeInsertQueueDpc
146 * @param SystemArgument2 Argument specified by KeInsertQueueDpc
147 */
148static VOID rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
149{
150 PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
151 ASMAtomicIncU32(&pArgs->cHits);
152 pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
153}
154
155
156/**
157 * Internal worker for the RTMpOn* APIs.
158 *
159 * @returns IPRT status code.
160 * @param pfnWorker The callback.
161 * @param pvUser1 User argument 1.
162 * @param pvUser2 User argument 2.
163 * @param enmCpuid What to do / is idCpu valid.
164 * @param idCpu Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
165 */
166static int rtMpCall(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
167{
168 PRTMPARGS pArgs;
169 KDPC *paExecCpuDpcs;
170
171#if 0
172 /* KeFlushQueuedDpcs must be run at IRQL PASSIVE_LEVEL according to MSDN, but the
173 * driver verifier doesn't complain...
174 */
175 AssertMsg(KeGetCurrentIrql() == PASSIVE_LEVEL, ("%d != %d (PASSIVE_LEVEL)\n", KeGetCurrentIrql(), PASSIVE_LEVEL));
176#endif
177
178 KAFFINITY Mask = KeQueryActiveProcessors();
179
180 /* KeFlushQueuedDpcs is not present in Windows 2000; import it dynamically so we can just fail this call. */
181 UNICODE_STRING RoutineName;
182 RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs");
183 VOID (*pfnKeFlushQueuedDpcs)(VOID) = (VOID (*)(VOID))MmGetSystemRoutineAddress(&RoutineName);
184 if (!pfnKeFlushQueuedDpcs)
185 return VERR_NOT_SUPPORTED;
186
187 pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_PROCESSORS*sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp');
188 if (!pArgs)
189 return VERR_NO_MEMORY;
190
191 pArgs->pfnWorker = pfnWorker;
192 pArgs->pvUser1 = pvUser1;
193 pArgs->pvUser2 = pvUser2;
194 pArgs->idCpu = NIL_RTCPUID;
195 pArgs->cHits = 0;
196
197 paExecCpuDpcs = (KDPC *)(pArgs + 1);
198
199 if (enmCpuid == RT_NT_CPUID_SPECIFIC)
200 {
201 KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs);
202 KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance);
203 KeSetTargetProcessorDpc(&paExecCpuDpcs[0], idCpu);
204 }
205 else
206 {
207 for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
208 {
209 KeInitializeDpc(&paExecCpuDpcs[i], rtmpNtDPCWrapper, pArgs);
210 KeSetImportanceDpc(&paExecCpuDpcs[i], HighImportance);
211 KeSetTargetProcessorDpc(&paExecCpuDpcs[i], i);
212 }
213 }
214
215 /* Raise the IRQL to DISPATCH_LEVEL so we can't be rescheduled to another cpu.
216 * KeInsertQueueDpc must also be executed at IRQL >= DISPATCH_LEVEL.
217 */
218 KIRQL oldIrql;
219 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
220
221 /*
222 * We cannot do other than assume a 1:1 relationship between the
223 * affinity mask and the process despite the warnings in the docs.
224 * If someone knows a better way to get this done, please let bird know.
225 */
226 if (enmCpuid == RT_NT_CPUID_SPECIFIC)
227 {
228 BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0);
229 Assert(ret);
230 }
231 else
232 {
233 unsigned iSelf = KeGetCurrentProcessorNumber();
234
235 for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++)
236 {
237 if ( (i != iSelf)
238 && (Mask & RT_BIT_64(i)))
239 {
240 BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[i], 0, 0);
241 Assert(ret);
242 }
243 }
244 if (enmCpuid != RT_NT_CPUID_OTHERS)
245 pfnWorker(iSelf, pvUser1, pvUser2);
246 }
247
248 KeLowerIrql(oldIrql);
249
250 /* Flush all DPCs and wait for completion. (can take long!) */
251 pfnKeFlushQueuedDpcs();
252
253 ExFreePool(pArgs);
254 return VINF_SUCCESS;
255}
256
257RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
258{
259 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
260}
261
262RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
263{
264 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
265}
266
267RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
268{
269 if (RTMpIsCpuOnline(idCpu);
270 return !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE;
271
272 return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
273}
274
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