VirtualBox

source: vbox/trunk/src/VBox/Additions/os2/VBoxGuest/VBoxGuest-os2.cpp@ 4968

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.2 KB
Line 
1/* $Id: VBoxGuest-os2.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
2/** @file
3 * VBoxGuest - OS/2 specifics.
4 */
5
6/*
7 * Copyright (C) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * VBoxDrv - OS/2 specifics.
21 *
22 * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
23 *
24 * Permission is hereby granted, free of charge, to any person
25 * obtaining a copy of this software and associated documentation
26 * files (the "Software"), to deal in the Software without
27 * restriction, including without limitation the rights to use,
28 * copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the
30 * Software is furnished to do so, subject to the following
31 * conditions:
32 *
33 * The above copyright notice and this permission notice shall be
34 * included in all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
37 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
38 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
39 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
40 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
41 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
42 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43 * OTHER DEALINGS IN THE SOFTWARE.
44 */
45
46
47/*******************************************************************************
48* Header Files *
49*******************************************************************************/
50#include <os2ddk/bsekee.h>
51
52#include "VBoxGuestInternal.h"
53#include <VBox/VBoxGuest.h>
54#include <VBox/version.h>
55#include <iprt/initterm.h>
56#include <iprt/string.h>
57#include <iprt/spinlock.h>
58#include <iprt/process.h>
59#include <iprt/assert.h>
60#include <iprt/log.h>
61
62
63/*******************************************************************************
64* Global Variables *
65*******************************************************************************/
66/**
67 * Device extention & session data association structure.
68 */
69static VBOXGUESTDEVEXT g_DevExt;
70/** Spinlock protecting g_apSessionHashTab. */
71static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
72/** Hash table */
73static PVBOXGUESTSESSION g_apSessionHashTab[19];
74/** Calculates the index into g_apSessionHashTab.*/
75#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
76
77__BEGIN_DECLS
78/* Defined in VBoxGuestA-os2.asm */
79extern uint32_t g_PhysMMIOBase;
80extern uint32_t g_cbMMIO; /* 0 currently not set. */
81extern uint16_t g_IOPortBase;
82extern uint8_t g_bInterruptLine;
83extern uint8_t g_bPciBusNo;
84extern uint8_t g_bPciDevFunNo;
85extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16;
86extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16Asm;
87#ifdef DEBUG_READ
88/* (debugging) */
89extern uint16_t g_offLogHead;
90extern uint16_t volatile g_offLogTail;
91extern uint16_t const g_cchLogMax;
92extern char g_szLog[];
93#endif
94/* (init only:) */
95extern char g_szInitText[];
96extern uint16_t g_cchInitText;
97extern uint16_t g_cchInitTextMax;
98__END_DECLS
99
100
101/*******************************************************************************
102* Internal Functions *
103*******************************************************************************/
104static VBOXOSTYPE vboxGuestOS2DetectVersion(void);
105
106/* in VBoxGuestA-os2.asm */
107DECLASM(int) VBoxGuestOS2SetIRQ(uint8_t bIRQ);
108
109
110/**
111 * 32-bit Ring-0 initialization.
112 *
113 * This is called from VBoxGuestA-os2.asm upon the first open call to the vboxgst$ device.
114 *
115 * @returns 0 on success, non-zero on failure.
116 * @param pszArgs Pointer to the device arguments.
117 */
118DECLASM(int) VBoxGuestOS2Init(const char *pszArgs)
119{
120 Log(("VBoxGuestOS2Init: pszArgs='%s' MMIO=0x%RX32 IOPort=0x%RX16 Int=%#x Bus=%#x Dev=%#x Fun=%d\n",
121 pszArgs, g_PhysMMIOBase, g_IOPortBase, g_bInterruptLine, g_bPciBusNo, g_bPciDevFunNo >> 3, g_bPciDevFunNo & 7));
122
123
124 /*
125 * Initialize the runtime.
126 */
127 int rc = RTR0Init(0);
128 if (RT_SUCCESS(rc))
129 {
130 /*
131 * Process the commandline. Later.
132 */
133 bool fVerbose = true;
134
135 /*
136 * Initialize the device extension.
137 */
138 rc = VBoxGuestInitDevExt(&g_DevExt, g_IOPortBase, g_PhysMMIOBase, vboxGuestOS2DetectVersion());
139 if (RT_SUCCESS(rc))
140 {
141 /*
142 * Initialize the session hash table.
143 */
144 rc = RTSpinlockCreate(&g_Spinlock);
145 if (RT_SUCCESS(rc))
146 {
147 /*
148 * Configure the interrupt handler.
149 */
150 if (g_bInterruptLine)
151 {
152 rc = VBoxGuestOS2SetIRQ(g_bInterruptLine);
153 if (rc)
154 {
155 Log(("VBoxGuestOS2SetIRQ(%d) -> %d\n", g_bInterruptLine, rc));
156 rc = RTErrConvertFromOS2(rc);
157 }
158 }
159 if (RT_SUCCESS(rc))
160 {
161 /*
162 * Success
163 */
164 if (fVerbose)
165 {
166 strcpy(&g_szInitText[0],
167 "\r\n"
168 "VirtualBox Guest Additions Driver for OS/2 version " VBOX_VERSION_STRING "\r\n"
169 "Copyright (C) 2007 innotek GmbH\r\n");
170 g_cchInitText = strlen(&g_szInitText[0]);
171 }
172 Log(("VBoxGuestOS2Init: Successfully loaded\n%s", g_szInitText));
173 return VINF_SUCCESS;
174 }
175
176 g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: SetIrq failed for IRQ %#d, rc=%Vrc\n",
177 g_bInterruptLine, rc);
178 }
179 else
180 g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTSpinlockCreate failed, rc=%Vrc\n", rc);
181 VBoxGuestDeleteDevExt(&g_DevExt);
182 }
183 else
184 g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: VBoxGuestOS2InitDevExt failed, rc=%Vrc\n", rc);
185 RTR0Term();
186 }
187 else
188 g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTR0Init failed, rc=%Vrc\n", rc);
189
190 RTLogBackdoorPrintf("VBoxGuestOS2Init: failed rc=%Vrc - %s", rc, &g_szInitText[0]);
191 return rc;
192}
193
194
195/**
196 * Called fromn VBoxGuestOS2Init to determin which OS/2 version this is.
197 *
198 * @returns VBox OS/2 type.
199 */
200static VBOXOSTYPE vboxGuestOS2DetectVersion(void)
201{
202 VBOXOSTYPE enmOSType = OSTypeOS2;
203
204#if 0 /** @todo dig up the version stuff from GIS later and verify that the numbers are actually decimal. */
205 unsigned uMajor, uMinor;
206 if (uMajor == 2)
207 {
208 if (uMinor >= 30 && uMinor < 40)
209 enmOSType = OSTypeOS2Warp3;
210 else if (uMinor >= 40 && uMinor < 45)
211 enmOSType = OSTypeOS2Warp4;
212 else if (uMinor >= 45 && uMinor < 50)
213 enmOSType = OSTypeOS2Warp45;
214 }
215#endif
216 return enmOSType;
217}
218
219
220DECLASM(int) VBoxGuestOS2Open(uint16_t sfn)
221{
222 int rc;
223 PVBOXGUESTSESSION pSession;
224
225 /*
226 * Create a new session.
227 */
228 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
229 if (RT_SUCCESS(rc))
230 {
231 pSession->sfn = sfn;
232
233 /*
234 * Insert it into the hash table.
235 */
236 unsigned iHash = SESSION_HASH(sfn);
237 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
238 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
239 pSession->pNextHash = g_apSessionHashTab[iHash];
240 g_apSessionHashTab[iHash] = pSession;
241 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
242 }
243
244 Log(("VBoxGuestOS2Open: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
245 return rc;
246}
247
248
249DECLASM(int) VBoxGuestOS2Close(uint16_t sfn)
250{
251 Log(("VBoxGuestOS2Close: pid=%d sfn=%d\n", (int)RTProcSelf(), sfn));
252
253 /*
254 * Remove from the hash table.
255 */
256 PVBOXGUESTSESSION pSession;
257 const RTPROCESS Process = RTProcSelf();
258 const unsigned iHash = SESSION_HASH(sfn);
259 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
260 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
261
262 pSession = g_apSessionHashTab[iHash];
263 if (pSession)
264 {
265 if ( pSession->sfn == sfn
266 && pSession->Process == Process)
267 {
268 g_apSessionHashTab[iHash] = pSession->pNextHash;
269 pSession->pNextHash = NULL;
270 }
271 else
272 {
273 PVBOXGUESTSESSION pPrev = pSession;
274 pSession = pSession->pNextHash;
275 while (pSession)
276 {
277 if ( pSession->sfn == sfn
278 && pSession->Process == Process)
279 {
280 pPrev->pNextHash = pSession->pNextHash;
281 pSession->pNextHash = NULL;
282 break;
283 }
284
285 /* next */
286 pPrev = pSession;
287 pSession = pSession->pNextHash;
288 }
289 }
290 }
291 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
292 if (!pSession)
293 {
294 Log(("VBoxGuestIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d sfn=%d\n", (int)Process, sfn));
295 return VERR_INVALID_PARAMETER;
296 }
297
298 /*
299 * Close the session.
300 */
301 VBoxGuestCloseSession(&g_DevExt, pSession);
302 return 0;
303}
304
305
306DECLASM(int) VBoxGuestOS2IOCtlFast(uint16_t sfn, uint8_t iFunction, int32_t *prc)
307{
308 /*
309 * Find the session.
310 */
311 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
312 const RTPROCESS Process = RTProcSelf();
313 const unsigned iHash = SESSION_HASH(sfn);
314 PVBOXGUESTSESSION pSession;
315
316 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
317 pSession = g_apSessionHashTab[iHash];
318 if (pSession && pSession->Process != Process)
319 {
320 do pSession = pSession->pNextHash;
321 while ( pSession
322 && ( pSession->sfn != sfn
323 || pSession->Process != Process));
324 }
325 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
326 if (RT_UNLIKELY(!pSession))
327 {
328 Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
329 return VERR_INVALID_PARAMETER;
330 }
331
332 /*
333 * Dispatch the fast IOCtl.
334 */
335 *prc = VBoxGuestCommonIOCtlFast(iFunction, &g_DevExt, pSession);
336 return 0;
337}
338
339
340/**
341 * 32-bit IDC service routine.
342 *
343 * @returns VBox status code.
344 * @param u32Session The session handle (PVBOXGUESTSESSION).
345 * @param iFunction The requested function.
346 * @param pvData The input/output data buffer. The caller ensures that this
347 * cannot be swapped out, or that it's acceptable to take a
348 * page in fault in the current context. If the request doesn't
349 * take input or produces output, apssing NULL is okay.
350 * @param cbData The size of the data buffer.
351 * @param pcbDataReturned Where to store the amount of data that's returned.
352 * This can be NULL if pvData is NULL.
353 *
354 * @remark This is called from the 16-bit thunker as well as directly from the 32-bit clients.
355 */
356DECLASM(int) VBoxGuestOS2IDCService(uint32_t u32Session, unsigned iFunction, void *pvData, size_t cbData, size_t *pcbDataReturned)
357{
358 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)u32Session;
359 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
360 AssertMsgReturn(pSession->sfn == 0xffff, ("%RX16\n", pSession->sfn), VERR_INVALID_HANDLE);
361 AssertMsgReturn(pSession->pDevExt == &g_DevExt, ("%p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
362
363 int rc;
364 switch (iFunction)
365 {
366 default:
367 rc = VBoxGuestCommonIOCtl(iFunction, &g_DevExt, pSession, pvData, cbData, pcbDataReturned);
368 break;
369
370 case VBOXGUEST_IOCTL_OS2_IDC_DISCONNECT:
371 pSession->sfn = 0;
372 VBoxGuestCloseSession(&g_DevExt, pSession);
373 rc = VINF_SUCCESS;
374 break;
375 }
376 return rc;
377}
378
379
380/**
381 * Worker for VBoxGuestOS2IDC, it creates the kernel session.
382 *
383 * @returns Pointer to the session.
384 */
385DECLASM(PVBOXGUESTSESSION) VBoxGuestOS2IDCConnect(void)
386{
387 PVBOXGUESTSESSION pSession;
388 int rc = VBoxGuestCreateKernelSession(&g_DevExt, &pSession);
389 if (RT_SUCCESS(rc))
390 {
391 pSession->sfn = 0xffff;
392 return pSession;
393 }
394 return NULL;
395}
396
397
398DECLASM(int) VBoxGuestOS2IOCtl(uint16_t sfn, uint8_t iCat, uint8_t iFunction, void *pvParm, void *pvData, uint16_t *pcbParm, uint16_t *pcbData)
399{
400 /*
401 * Find the session.
402 */
403 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
404 const RTPROCESS Process = RTProcSelf();
405 const unsigned iHash = SESSION_HASH(sfn);
406 PVBOXGUESTSESSION pSession;
407
408 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
409 pSession = g_apSessionHashTab[iHash];
410 if (pSession && pSession->Process != Process)
411 {
412 do pSession = pSession->pNextHash;
413 while ( pSession
414 && ( pSession->sfn != sfn
415 || pSession->Process != Process));
416 }
417 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
418 if (!pSession)
419 {
420 Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
421 return VERR_INVALID_PARAMETER;
422 }
423
424 /*
425 * Verify the category and dispatch the IOCtl.
426 *
427 * The IOCtl call uses the parameter buffer as generic data input/output
428 * buffer similar to the one unix ioctl buffer argument. While the data
429 * buffer is used for passing the VBox status code back to the caller
430 * since the status codes that OS/2 accepts thru the DosDevIOCtl API is
431 * severely restricted.
432 */
433 if (RT_LIKELY(iCat == VBOXGUEST_IOCTL_CATEGORY))
434 {
435 Log(("VBoxGuestOS2IOCtl: pSession=%p iFunction=%#x pvParm=%p pvData=%p *pcbParm=%d *pcbData=%d\n", pSession, iFunction, pvParm, pvData, *pcbParm, *pcbData));
436 Assert(pvParm || !*pcbData);
437 Assert(pvData);
438 Assert(*pcbData == sizeof(int32_t)); /* the return code */
439
440 /*
441 * Lock the buffers.
442 */
443 int32_t rc;
444 KernVMLock_t ParmLock;
445 if (pvParm)
446 {
447 Assert(*pcbData);
448 rc = KernVMLock(VMDHL_WRITE, pvParm, *pcbParm, &ParmLock, (KernPageList_t *)-1, NULL);
449 AssertMsgReturn(!rc, ("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pvParm, *pcbParm, &ParmLock, rc), VERR_LOCK_FAILED);
450 }
451
452#if 0 /* don't bother locking it since it's only 4 bytes (the return code). */
453 KernVMLock_t DataLock;
454 if (pvData)
455 {
456 Assert(*pcbData);
457 rc = KernVMLock(VMDHL_WRITE, pvData, *pcbData, &DataLock, (KernPageList_t *)-1, NULL);
458 if (rc)
459 {
460 AssertMsgFailed(("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pvData, *pcbData, &DataLock, rc));
461 KernVMUnlock(&ParmLock);
462 return VERR_LOCK_FAILED;
463 }
464 }
465#endif
466
467 /*
468 * Process the IOCtl.
469 */
470 size_t cbDataReturned = 0;
471 rc = VBoxGuestCommonIOCtl(iFunction, &g_DevExt, pSession,
472 pvParm, *pcbParm, &cbDataReturned);
473
474 /*
475 * Unlock the buffers.
476 */
477 if (pvParm)
478 {
479 int rc2 = KernVMUnlock(&ParmLock);
480 AssertMsg(!rc2, ("rc2=%d\n", rc2)); NOREF(rc2);
481 AssertMsg(cbDataReturned < _64K, ("cbDataReturned=%d\n", cbDataReturned));
482 *pcbParm = cbDataReturned;
483 }
484#if 0
485 if (pvData)
486 {
487 int rc2 = KernVMUnlock(&DataLock);
488 AssertMsg(!rc2, ("rc2=%d\n", rc2));
489 }
490#else
491 rc = KernCopyOut(pvData, &rc, sizeof(int32_t));
492 AssertMsgReturn(!rc, ("KernCopyOut(%p, %p, sizeof(int32_t)) -> %d\n", pvData, &rc, rc), VERR_LOCK_FAILED);
493#endif
494
495 Log2(("VBoxGuestOS2IOCtl: returns VINF_SUCCESS / %d\n", rc));
496 return VINF_SUCCESS;
497 }
498 return VERR_NOT_SUPPORTED;
499}
500
501
502/**
503 * 32-bit ISR, called by 16-bit assembly thunker in VBoxGuestA-os2.asm.
504 *
505 * @returns true if it's our interrupt, false it isn't.
506 */
507DECLASM(bool) VBoxGuestOS2ISR(void)
508{
509 Log(("VBoxGuestOS2ISR\n"));
510
511 return VBoxGuestCommonISR(&g_DevExt);
512}
513
514
515#ifdef DEBUG_READ /** @todo figure out this one once and for all... */
516
517/**
518 * Callback for writing to the log buffer.
519 *
520 * @returns number of bytes written.
521 * @param pvArg Unused.
522 * @param pachChars Pointer to an array of utf-8 characters.
523 * @param cbChars Number of bytes in the character array pointed to by pachChars.
524 */
525static DECLCALLBACK(size_t) vboxGuestNativeLogOutput(void *pvArg, const char *pachChars, size_t cbChars)
526{
527 size_t cchWritten = 0;
528 while (cbChars-- > 0)
529 {
530 const uint16_t offLogHead = g_offLogHead;
531 const uint16_t offLogHeadNext = (offLogHead + 1) & (g_cchLogMax - 1);
532 if (offLogHeadNext == g_offLogTail)
533 break; /* no */
534 g_szLog[offLogHead] = *pachChars++;
535 g_offLogHead = offLogHeadNext;
536 cchWritten++;
537 }
538 return cchWritten;
539}
540
541
542int SUPR0Printf(const char *pszFormat, ...)
543{
544 va_list va;
545
546#if 0 //def DEBUG_bird
547 va_start(va, pszFormat);
548 RTLogComPrintfV(pszFormat, va);
549 va_end(va);
550#endif
551
552 va_start(va, pszFormat);
553 int cch = RTLogFormatV(vboxGuestNativeLogOutput, NULL, pszFormat, va);
554 va_end(va);
555
556 return cch;
557}
558
559#endif /* DEBUG_READ */
560
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