VirtualBox

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

Last change on this file since 3657 was 3657, checked in by vboxsync, 18 years ago

export

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