VirtualBox

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

Last change on this file since 40282 was 37596, checked in by vboxsync, 13 years ago

*: RTFILE becomes a pointer, RTFileOpen++ expands it's flags paramter from uint32_t to uint64_t.

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