VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp@ 13858

Last change on this file since 13858 was 13858, checked in by vboxsync, 16 years ago

Pass the VMCPU id to the ring 0 callbacks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/* $Id: SUPLib-win.cpp 13858 2008-11-05 13:45:41Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Windows NT specific parts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP
35#ifdef IN_SUP_HARDENED_R3
36# undef DEBUG /* Warning: disables RT_STRICT */
37# define LOG_DISABLED
38 /** @todo RTLOGREL_DISABLED */
39# include <iprt/log.h>
40# undef LogRelIt
41# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
42#endif
43
44#include <Windows.h>
45
46#include <VBox/sup.h>
47#include <VBox/types.h>
48#include <VBox/err.h>
49#include <VBox/param.h>
50#include <VBox/log.h>
51#include <iprt/assert.h>
52#include <iprt/path.h>
53#include <iprt/string.h>
54#include "../SUPLibInternal.h"
55#include "../SUPDrvIOC.h"
56
57
58/*******************************************************************************
59* Defined Constants And Macros *
60*******************************************************************************/
61/** The support service name. */
62#define SERVICE_NAME "VBoxDrv"
63/** Win32 Device name. */
64#define DEVICE_NAME "\\\\.\\VBoxDrv"
65/** NT Device name. */
66#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
67/** Win32 Symlink name. */
68#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
69
70
71/*******************************************************************************
72* Internal Functions *
73*******************************************************************************/
74static int suplibOsCreateService(void);
75//unused: static int suplibOsUpdateService(void);
76static int suplibOsDeleteService(void);
77static int suplibOsStartService(void);
78static int suplibOsStopService(void);
79static int suplibConvertWin32Err(int);
80
81
82
83
84int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
85{
86 /*
87 * Nothing to do if pre-inited.
88 */
89 if (fPreInited)
90 return VINF_SUCCESS;
91
92 /*
93 * Try open the device.
94 */
95 HANDLE hDevice = CreateFile(DEVICE_NAME,
96 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
97 NULL,
98 OPEN_EXISTING,
99 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
100 NULL);
101 if (hDevice == INVALID_HANDLE_VALUE)
102 {
103#ifndef IN_SUP_HARDENED_R3
104 /*
105 * Try start the service and retry opening it.
106 */
107 suplibOsStartService();
108
109 hDevice = CreateFile(DEVICE_NAME,
110 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
111 NULL,
112 OPEN_EXISTING,
113 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
114 NULL);
115 if (hDevice == INVALID_HANDLE_VALUE)
116#endif /* !IN_SUP_HARDENED_R3 */
117 {
118 int rc = GetLastError();
119 switch (rc)
120 {
121 /** @todo someone must test what is actually returned. */
122 case ERROR_DEV_NOT_EXIST:
123 case ERROR_DEVICE_NOT_CONNECTED:
124 case ERROR_BAD_DEVICE:
125 case ERROR_DEVICE_REMOVED:
126 case ERROR_DEVICE_NOT_AVAILABLE:
127 return VERR_VM_DRIVER_LOAD_ERROR;
128 case ERROR_PATH_NOT_FOUND:
129 case ERROR_FILE_NOT_FOUND:
130 return VERR_VM_DRIVER_NOT_INSTALLED;
131 case ERROR_ACCESS_DENIED:
132 case ERROR_SHARING_VIOLATION:
133 return VERR_VM_DRIVER_NOT_ACCESSIBLE;
134 default:
135 return VERR_VM_DRIVER_OPEN_ERROR;
136 }
137
138 return -1 /** @todo define proper error codes for suplibOsInit failure. */;
139 }
140 }
141
142 /*
143 * We're done.
144 */
145 pThis->hDevice = (RTFILE)hDevice;
146 return VINF_SUCCESS;
147}
148
149
150#ifndef IN_SUP_HARDENED_R3
151
152int suplibOsInstall(void)
153{
154 return suplibOsCreateService();
155}
156
157
158int suplibOsUninstall(void)
159{
160 int rc = suplibOsStopService();
161 if (!rc)
162 rc = suplibOsDeleteService();
163 return rc;
164}
165
166
167/**
168 * Creates the service.
169 *
170 * @returns 0 on success.
171 * @returns -1 on failure.
172 */
173static int suplibOsCreateService(void)
174{
175 /*
176 * Assume it didn't exist, so we'll create the service.
177 */
178 SC_HANDLE hSMgrCreate = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
179 DWORD LastError = GetLastError(); NOREF(LastError);
180 AssertMsg(hSMgrCreate, ("OpenSCManager(,,create) failed rc=%d\n", LastError));
181 if (hSMgrCreate)
182 {
183 char szDriver[RTPATH_MAX];
184 int rc = RTPathProgram(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
185 if (RT_SUCCESS(rc))
186 {
187 strcat(szDriver, "\\VBoxDrv.sys");
188 SC_HANDLE hService = CreateService(hSMgrCreate,
189 SERVICE_NAME,
190 "VBox Support Driver",
191 SERVICE_QUERY_STATUS,
192 SERVICE_KERNEL_DRIVER,
193 SERVICE_DEMAND_START,
194 SERVICE_ERROR_NORMAL,
195 szDriver,
196 NULL, NULL, NULL, NULL, NULL);
197 DWORD LastError = GetLastError(); NOREF(LastError);
198 AssertMsg(hService, ("CreateService failed! LastError=%Rwa szDriver=%s\n", LastError, szDriver));
199 CloseServiceHandle(hService);
200 CloseServiceHandle(hSMgrCreate);
201 return hService ? 0 : -1;
202 }
203 CloseServiceHandle(hSMgrCreate);
204 return rc;
205 }
206 return -1;
207}
208
209
210/**
211 * Stops a possibly running service.
212 *
213 * @returns 0 on success.
214 * @returns -1 on failure.
215 */
216static int suplibOsStopService(void)
217{
218 /*
219 * Assume it didn't exist, so we'll create the service.
220 */
221 int rc = -1;
222 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_STOP | SERVICE_QUERY_STATUS);
223 DWORD LastError = GetLastError(); NOREF(LastError);
224 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", LastError));
225 if (hSMgr)
226 {
227 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
228 if (hService)
229 {
230 /*
231 * Stop the service.
232 */
233 SERVICE_STATUS Status;
234 QueryServiceStatus(hService, &Status);
235 if (Status.dwCurrentState == SERVICE_STOPPED)
236 rc = 0;
237 else if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
238 {
239 int iWait = 100;
240 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
241 {
242 Sleep(100);
243 QueryServiceStatus(hService, &Status);
244 }
245 if (Status.dwCurrentState == SERVICE_STOPPED)
246 rc = 0;
247 else
248 AssertMsgFailed(("Failed to stop service. status=%d\n", Status.dwCurrentState));
249 }
250 else
251 {
252 DWORD LastError = GetLastError(); NOREF(LastError);
253 AssertMsgFailed(("ControlService failed with LastError=%Rwa. status=%d\n", LastError, Status.dwCurrentState));
254 }
255 CloseServiceHandle(hService);
256 }
257 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
258 rc = 0;
259 else
260 {
261 DWORD LastError = GetLastError(); NOREF(LastError);
262 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
263 }
264 CloseServiceHandle(hSMgr);
265 }
266 return rc;
267}
268
269
270/**
271 * Deletes the service.
272 *
273 * @returns 0 on success.
274 * @returns -1 on failure.
275 */
276int suplibOsDeleteService(void)
277{
278 /*
279 * Assume it didn't exist, so we'll create the service.
280 */
281 int rc = -1;
282 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
283 DWORD LastError = GetLastError(); NOREF(LastError);
284 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", LastError));
285 if (hSMgr)
286 {
287 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, DELETE);
288 if (hService)
289 {
290 /*
291 * Delete the service.
292 */
293 if (DeleteService(hService))
294 rc = 0;
295 else
296 {
297 DWORD LastError = GetLastError(); NOREF(LastError);
298 AssertMsgFailed(("DeleteService failed LastError=%Rwa\n", LastError));
299 }
300 CloseServiceHandle(hService);
301 }
302 else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
303 rc = 0;
304 else
305 {
306 DWORD LastError = GetLastError(); NOREF(LastError);
307 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
308 }
309 CloseServiceHandle(hSMgr);
310 }
311 return rc;
312}
313
314#if 0
315/**
316 * Creates the service.
317 *
318 * @returns 0 on success.
319 * @returns -1 on failure.
320 */
321static int suplibOsUpdateService(void)
322{
323 /*
324 * Assume it didn't exist, so we'll create the service.
325 */
326 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
327 DWORD LastError = GetLastError(); NOREF(LastError);
328 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed LastError=%Rwa\n", LastError));
329 if (hSMgr)
330 {
331 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_CHANGE_CONFIG);
332 if (hService)
333 {
334 char szDriver[RTPATH_MAX];
335 int rc = RTPathProgram(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
336 if (RT_SUCCESS(rc))
337 {
338 strcat(szDriver, "\\VBoxDrv.sys");
339
340 SC_LOCK hLock = LockServiceDatabase(hSMgr);
341 if (ChangeServiceConfig(hService,
342 SERVICE_KERNEL_DRIVER,
343 SERVICE_DEMAND_START,
344 SERVICE_ERROR_NORMAL,
345 szDriver,
346 NULL, NULL, NULL, NULL, NULL, NULL))
347 {
348
349 UnlockServiceDatabase(hLock);
350 CloseServiceHandle(hService);
351 CloseServiceHandle(hSMgr);
352 return 0;
353 }
354 else
355 {
356 DWORD LastError = GetLastError(); NOREF(LastError);
357 AssertMsgFailed(("ChangeServiceConfig failed LastError=%Rwa\n", LastError));
358 }
359 }
360 UnlockServiceDatabase(hLock);
361 CloseServiceHandle(hService);
362 }
363 else
364 {
365 DWORD LastError = GetLastError(); NOREF(LastError);
366 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
367 }
368 CloseServiceHandle(hSMgr);
369 }
370 return -1;
371}
372#endif
373
374
375/**
376 * Attempts to start the service, creating it if necessary.
377 *
378 * @returns 0 on success.
379 * @returns -1 on failure.
380 * @param fRetry Indicates retry call.
381 */
382static int suplibOsStartService(void)
383{
384 /*
385 * Check if the driver service is there.
386 */
387 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_START);
388 if (hSMgr == NULL)
389 {
390 AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode!\n"));
391 return -1;
392 }
393
394 /*
395 * Try open our service to check it's status.
396 */
397 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
398 if (!hService)
399 {
400 /*
401 * Create the service.
402 */
403 int rc = suplibOsCreateService();
404 if (rc)
405 return rc;
406
407 /*
408 * Try open the service.
409 */
410 hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
411 }
412
413 /*
414 * Check if open and on demand create succeeded.
415 */
416 int rc = -1;
417 if (hService)
418 {
419
420 /*
421 * Query service status to see if we need to start it or not.
422 */
423 SERVICE_STATUS Status;
424 BOOL fRc = QueryServiceStatus(hService, &Status);
425 Assert(fRc);
426 if ( Status.dwCurrentState != SERVICE_RUNNING
427 && Status.dwCurrentState != SERVICE_START_PENDING)
428 {
429 /*
430 * Start it.
431 */
432 fRc = StartService(hService, 0, NULL);
433 DWORD LastError = GetLastError(); NOREF(LastError);
434 AssertMsg(fRc, ("StartService failed with LastError=%Rwa\n", LastError));
435 }
436
437 /*
438 * Wait for the service to finish starting.
439 * We'll wait for 10 seconds then we'll give up.
440 */
441 QueryServiceStatus(hService, &Status);
442 if (Status.dwCurrentState == SERVICE_START_PENDING)
443 {
444 int iWait;
445 for (iWait = 100; iWait > 0 && Status.dwCurrentState == SERVICE_START_PENDING; iWait--)
446 {
447 Sleep(100);
448 QueryServiceStatus(hService, &Status);
449 }
450 DWORD LastError = GetLastError(); NOREF(LastError);
451 AssertMsg(Status.dwCurrentState != SERVICE_RUNNING,
452 ("Failed to start. LastError=%Rwa iWait=%d status=%d\n",
453 LastError, iWait, Status.dwCurrentState));
454 }
455
456 if (Status.dwCurrentState == SERVICE_RUNNING)
457 rc = 0;
458
459 /*
460 * Close open handles.
461 */
462 CloseServiceHandle(hService);
463 }
464 else
465 {
466 DWORD LastError = GetLastError(); NOREF(LastError);
467 AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", LastError));
468 }
469 if (!CloseServiceHandle(hSMgr))
470 AssertFailed();
471
472 return rc;
473}
474
475
476int suplibOsTerm(PSUPLIBDATA pThis)
477{
478 /*
479 * Check if we're initited at all.
480 */
481 if (pThis->hDevice != NIL_RTFILE)
482 {
483 if (!CloseHandle((HANDLE)pThis->hDevice))
484 AssertFailed();
485 pThis->hDevice = NIL_RTFILE;
486 }
487
488 return VINF_SUCCESS;
489}
490
491
492int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
493{
494 /*
495 * Issue the device I/O control.
496 */
497 PSUPREQHDR pHdr = (PSUPREQHDR)pvReq;
498 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut));
499 DWORD cbReturned = (ULONG)pHdr->cbOut;
500 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
501 return 0;
502 return suplibConvertWin32Err(GetLastError());
503}
504
505
506int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, unsigned idCpu)
507{
508 /*
509 * Issue device I/O control.
510 */
511 DWORD cbReturned = 0;
512 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
513 return VINF_SUCCESS;
514 return suplibConvertWin32Err(GetLastError());
515}
516
517
518int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
519{
520 NOREF(pThis);
521 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
522 if (*ppvPages)
523 return VINF_SUCCESS;
524 return suplibConvertWin32Err(GetLastError());
525}
526
527
528int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
529{
530 NOREF(pThis);
531 if (VirtualFree(pvPages, 0, MEM_RELEASE))
532 return VINF_SUCCESS;
533 return suplibConvertWin32Err(GetLastError());
534}
535
536
537/**
538 * Converts a supdrv error code to an nt status code.
539 *
540 * @returns corresponding SUPDRV_ERR_*.
541 * @param rc Win32 error code.
542 */
543static int suplibConvertWin32Err(int rc)
544{
545 /* Conversion program (link with ntdll.lib from ddk):
546 #define _WIN32_WINNT 0x0501
547 #include <windows.h>
548 #include <ntstatus.h>
549 #include <winternl.h>
550 #include <stdio.h>
551
552 int main()
553 {
554 #define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
555 CONVERT(STATUS_SUCCESS);
556 CONVERT(STATUS_NOT_SUPPORTED);
557 CONVERT(STATUS_INVALID_PARAMETER);
558 CONVERT(STATUS_UNKNOWN_REVISION);
559 CONVERT(STATUS_INVALID_HANDLE);
560 CONVERT(STATUS_INVALID_ADDRESS);
561 CONVERT(STATUS_NOT_LOCKED);
562 CONVERT(STATUS_IMAGE_ALREADY_LOADED);
563 CONVERT(STATUS_ACCESS_DENIED);
564 CONVERT(STATUS_REVISION_MISMATCH);
565
566 return 0;
567 }
568 */
569
570 switch (rc)
571 {
572 //case 0: return STATUS_SUCCESS;
573 case 0: return VINF_SUCCESS;
574 //case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
575 case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
576 //case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
577 case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
578 //case SUPDRV_ERR_INVALID_MAGIC: return STATUS_ACCESS_DENIED;
579 case ERROR_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
580 //case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
581 case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
582 //case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
583 case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
584 //case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
585 case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
586 //case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
587 case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
588 //case SUPDRV_ERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
589 case ERROR_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
590 //case SUPDRV_ERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
591 case ERROR_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
592 }
593
594 /* fall back on the default conversion. */
595 return RTErrConvertFromWin32(rc);
596}
597
598#endif /* !IN_SUP_HARDENED_R3 */
599
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