diff options
Diffstat (limited to 'src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp')
-rw-r--r-- | src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp new file mode 100644 index 00000000..499296c8 --- /dev/null +++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-os2.cpp @@ -0,0 +1,688 @@ +/* $Id: VBoxGuest-os2.cpp $ */ +/** @file + * VBoxGuest - OS/2 specifics. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * --------------------------------------------------------------------------- + * This code is based on: + * + * VBoxDrv - OS/2 specifics. + * + * Copyright (c) 2007-2012 knut st. osmundsen <bird-src-spam@anduin.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <os2ddk/bsekee.h> + +#include "VBoxGuestInternal.h" +#include <VBox/version.h> +#include <iprt/assert.h> +#include <iprt/err.h> +#include <iprt/initterm.h> +#include <iprt/log.h> +#include <iprt/memobj.h> +#include <iprt/mem.h> +#include <iprt/param.h> +#include <iprt/process.h> +#include <iprt/spinlock.h> +#include <iprt/string.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** + * Device extention & session data association structure. + */ +static VBOXGUESTDEVEXT g_DevExt; +/** The memory object for the MMIO memory. */ +static RTR0MEMOBJ g_MemObjMMIO = NIL_RTR0MEMOBJ; +/** The memory mapping object the MMIO memory. */ +static RTR0MEMOBJ g_MemMapMMIO = NIL_RTR0MEMOBJ; + +/** Spinlock protecting g_apSessionHashTab. */ +static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK; +/** Hash table */ +static PVBOXGUESTSESSION g_apSessionHashTab[19]; +/** Calculates the index into g_apSessionHashTab.*/ +#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab)) + +RT_C_DECLS_BEGIN +/* Defined in VBoxGuestA-os2.asm */ +extern uint32_t g_PhysMMIOBase; +extern uint32_t g_cbMMIO; /* 0 currently not set. */ +extern uint16_t g_IOPortBase; +extern uint8_t g_bInterruptLine; +extern uint8_t g_bPciBusNo; +extern uint8_t g_bPciDevFunNo; +extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16; +extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16Asm; +#ifdef DEBUG_READ +/* (debugging) */ +extern uint16_t g_offLogHead; +extern uint16_t volatile g_offLogTail; +extern uint16_t const g_cchLogMax; +extern char g_szLog[]; +#endif +/* (init only:) */ +extern char g_szInitText[]; +extern uint16_t g_cchInitText; +extern uint16_t g_cchInitTextMax; +RT_C_DECLS_END + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +static int vgdrvOS2MapMemory(void); +static VBOXOSTYPE vgdrvOS2DetectVersion(void); + +/* in VBoxGuestA-os2.asm */ +DECLASM(int) vgdrvOS2DevHlpSetIRQ(uint8_t bIRQ); + + +/** + * 32-bit Ring-0 initialization. + * + * This is called from VBoxGuestA-os2.asm upon the first open call to the vboxgst$ device. + * + * @returns 0 on success, non-zero on failure. + * @param pszArgs Pointer to the device arguments. + */ +DECLASM(int) vgdrvOS2Init(const char *pszArgs) +{ + //Log(("vgdrvOS2Init: pszArgs='%s' MMIO=0x%RX32 IOPort=0x%RX16 Int=%#x Bus=%#x Dev=%#x Fun=%d\n", + // pszArgs, g_PhysMMIOBase, g_IOPortBase, g_bInterruptLine, g_bPciBusNo, g_bPciDevFunNo >> 3, g_bPciDevFunNo & 7)); + + /* + * Initialize the runtime. + */ + int rc = RTR0Init(0); + if (RT_SUCCESS(rc)) + { + /* + * Process the command line. + */ + bool fVerbose = true; + if (pszArgs) + { + char ch; + while ((ch = *pszArgs++) != '\0') + if (ch == '-' || ch == '/') + { + ch = *pszArgs++; + if (ch == 'Q' || ch == 'q') + fVerbose = false; + else if (ch == 'V' || ch == 'v') + fVerbose = true; + else if (ch == '\0') + break; + /*else: ignore stuff we don't know what is */ + } + /* else: skip spaces and unknown stuff */ + } + + /* + * Map the MMIO memory if found. + */ + rc = vgdrvOS2MapMemory(); + if (RT_SUCCESS(rc)) + { + /* + * Initialize the device extension. + */ + if (g_MemMapMMIO != NIL_RTR0MEMOBJ) + rc = VGDrvCommonInitDevExt(&g_DevExt, g_IOPortBase, + RTR0MemObjAddress(g_MemMapMMIO), + RTR0MemObjSize(g_MemMapMMIO), + vgdrvOS2DetectVersion(), + 0); + else + rc = VGDrvCommonInitDevExt(&g_DevExt, g_IOPortBase, NULL, 0, vgdrvOS2DetectVersion(), 0); + if (RT_SUCCESS(rc)) + { + /* + * Initialize the session hash table. + */ + rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestOS2"); + if (RT_SUCCESS(rc)) + { + /* + * Configure the interrupt handler. + */ + if (g_bInterruptLine) + { + rc = vgdrvOS2DevHlpSetIRQ(g_bInterruptLine); + if (rc) + { + Log(("vgdrvOS2DevHlpSetIRQ(%d) -> %d\n", g_bInterruptLine, rc)); + rc = RTErrConvertFromOS2(rc); + } + } + if (RT_SUCCESS(rc)) + { + /* + * Read host configuration. + */ + VGDrvCommonProcessOptionsFromHost(&g_DevExt); + + /* + * Success + */ + if (fVerbose) + { + strcpy(&g_szInitText[0], + "\r\n" + "VirtualBox Guest Additions Driver for OS/2 version " VBOX_VERSION_STRING "\r\n" + "Copyright (C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\r\n"); + g_cchInitText = strlen(&g_szInitText[0]); + } + Log(("vgdrvOS2Init: Successfully loaded\n%s", g_szInitText)); + return VINF_SUCCESS; + } + + g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: SetIrq failed for IRQ %#d, rc=%Rrc\n", + g_bInterruptLine, rc); + } + else + g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTSpinlockCreate failed, rc=%Rrc\n", rc); + VGDrvCommonDeleteDevExt(&g_DevExt); + } + else + g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: vgdrvOS2InitDevExt failed, rc=%Rrc\n", rc); + + int rc2 = RTR0MemObjFree(g_MemObjMMIO, true /* fFreeMappings */); AssertRC(rc2); + g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ; + } + else + g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: VBoxGuestOS2MapMMIO failed, rc=%Rrc\n", rc); + RTR0Term(); + } + else + g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTR0Init failed, rc=%Rrc\n", rc); + + RTLogBackdoorPrintf("vgdrvOS2Init: failed rc=%Rrc - %s", rc, &g_szInitText[0]); + return rc; +} + + +/** + * Maps the VMMDev memory. + * + * @returns VBox status code. + * @retval VERR_VERSION_MISMATCH The VMMDev memory didn't meet our expectations. + */ +static int vgdrvOS2MapMemory(void) +{ + const RTCCPHYS PhysMMIOBase = g_PhysMMIOBase; + + /* + * Did we find any MMIO region (0 or NIL)? + */ + if ( !PhysMMIOBase + || PhysMMIOBase == NIL_RTCCPHYS) + { + Assert(g_MemMapMMIO != NIL_RTR0MEMOBJ); + return VINF_SUCCESS; + } + + /* + * Create a physical memory object for it. + * + * Since we don't know the actual size (OS/2 doesn't at least), we make + * a qualified guess using the VMMDEV_RAM_SIZE. + */ + size_t cb = RT_ALIGN_Z(VMMDEV_RAM_SIZE, PAGE_SIZE); + int rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE); + if (RT_FAILURE(rc)) + { + cb = _4K; + rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE); + } + if (RT_FAILURE(rc)) + { + Log(("vgdrvOS2MapMemory: RTR0MemObjEnterPhys(,%RCp,%zx) -> %Rrc\n", PhysMMIOBase, cb, rc)); + return rc; + } + + /* + * Map the object into kernel space. + * + * We want a normal mapping with normal caching, which good in two ways. First + * since the API doesn't have any flags indicating how the mapping should be cached. + * And second, because PGM doesn't necessarily respect the cache/writethru bits + * anyway for normal RAM. + */ + rc = RTR0MemObjMapKernel(&g_MemMapMMIO, g_MemObjMMIO, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE); + if (RT_SUCCESS(rc)) + { + /* + * Validate the VMM memory. + */ + VMMDevMemory *pVMMDev = (VMMDevMemory *)RTR0MemObjAddress(g_MemMapMMIO); + Assert(pVMMDev); + if ( pVMMDev->u32Version == VMMDEV_MEMORY_VERSION + && pVMMDev->u32Size >= 32 /* just for checking sanity */) + { + /* + * Did we hit the correct size? If not we'll have to + * redo the mapping using the correct size. + */ + if (RT_ALIGN_32(pVMMDev->u32Size, PAGE_SIZE) == cb) + return VINF_SUCCESS; + + Log(("vgdrvOS2MapMemory: Actual size %#RX32 (tried %#zx)\n", pVMMDev->u32Size, cb)); + cb = RT_ALIGN_32(pVMMDev->u32Size, PAGE_SIZE); + + rc = RTR0MemObjFree(g_MemObjMMIO, true); AssertRC(rc); + g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ; + + rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE); + if (RT_SUCCESS(rc)) + { + rc = RTR0MemObjMapKernel(&g_MemMapMMIO, g_MemObjMMIO, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + + Log(("vgdrvOS2MapMemory: RTR0MemObjMapKernel [%RCp,%zx] -> %Rrc (2nd)\n", PhysMMIOBase, cb, rc)); + } + else + Log(("vgdrvOS2MapMemory: RTR0MemObjEnterPhys(,%RCp,%zx) -> %Rrc (2nd)\n", PhysMMIOBase, cb, rc)); + } + else + { + rc = VERR_VERSION_MISMATCH; + LogRel(("vgdrvOS2MapMemory: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32\n", + pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size)); + } + } + else + Log(("vgdrvOS2MapMemory: RTR0MemObjMapKernel [%RCp,%zx] -> %Rrc\n", PhysMMIOBase, cb, rc)); + + int rc2 = RTR0MemObjFree(g_MemObjMMIO, true /* fFreeMappings */); AssertRC(rc2); + g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ; + return rc; +} + + +/** + * Called fromn vgdrvOS2Init to determine which OS/2 version this is. + * + * @returns VBox OS/2 type. + */ +static VBOXOSTYPE vgdrvOS2DetectVersion(void) +{ + VBOXOSTYPE enmOSType = VBOXOSTYPE_OS2; + +#if 0 /** @todo dig up the version stuff from GIS later and verify that the numbers are actually decimal. */ + unsigned uMajor, uMinor; + if (uMajor == 2) + { + if (uMinor >= 30 && uMinor < 40) + enmOSType = VBOXOSTYPE_OS2Warp3; + else if (uMinor >= 40 && uMinor < 45) + enmOSType = VBOXOSTYPE_OS2Warp4; + else if (uMinor >= 45 && uMinor < 50) + enmOSType = VBOXOSTYPE_OS2Warp45; + } +#endif + return enmOSType; +} + + +DECLASM(int) vgdrvOS2Open(uint16_t sfn) +{ + int rc; + PVBOXGUESTSESSION pSession; + + /* + * Create a new session. + */ + uint32_t fRequestor = VMMDEV_REQUESTOR_USERMODE + | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN + | VMMDEV_REQUESTOR_USR_ROOT /* everyone is root on OS/2 */ + | VMMDEV_REQUESTOR_GRP_WHEEL /* and their admins */ + | VMMDEV_REQUESTOR_NO_USER_DEVICE /** @todo implement /dev/vboxuser? */ + | VMMDEV_REQUESTOR_CON_DONT_KNOW; /** @todo check screen group/whatever of process to see if console */ + rc = VGDrvCommonCreateUserSession(&g_DevExt, fRequestor, &pSession); + if (RT_SUCCESS(rc)) + { + pSession->sfn = sfn; + + /* + * Insert it into the hash table. + */ + unsigned iHash = SESSION_HASH(sfn); + RTSpinlockAcquire(g_Spinlock); + pSession->pNextHash = g_apSessionHashTab[iHash]; + g_apSessionHashTab[iHash] = pSession; + RTSpinlockRelease(g_Spinlock); + } + + Log(("vgdrvOS2Open: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf())); + return rc; +} + + +DECLASM(int) vgdrvOS2Close(uint16_t sfn) +{ + Log(("vgdrvOS2Close: pid=%d sfn=%d\n", (int)RTProcSelf(), sfn)); + + /* + * Remove from the hash table. + */ + PVBOXGUESTSESSION pSession; + const RTPROCESS Process = RTProcSelf(); + const unsigned iHash = SESSION_HASH(sfn); + RTSpinlockAcquire(g_Spinlock); + + pSession = g_apSessionHashTab[iHash]; + if (pSession) + { + if ( pSession->sfn == sfn + && pSession->Process == Process) + { + g_apSessionHashTab[iHash] = pSession->pNextHash; + pSession->pNextHash = NULL; + } + else + { + PVBOXGUESTSESSION pPrev = pSession; + pSession = pSession->pNextHash; + while (pSession) + { + if ( pSession->sfn == sfn + && pSession->Process == Process) + { + pPrev->pNextHash = pSession->pNextHash; + pSession->pNextHash = NULL; + break; + } + + /* next */ + pPrev = pSession; + pSession = pSession->pNextHash; + } + } + } + RTSpinlockRelease(g_Spinlock); + if (!pSession) + { + Log(("VBoxGuestIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d sfn=%d\n", (int)Process, sfn)); + return VERR_INVALID_PARAMETER; + } + + /* + * Close the session. + */ + VGDrvCommonCloseSession(&g_DevExt, pSession); + return 0; +} + + +DECLASM(int) vgdrvOS2IOCtlFast(uint16_t sfn, uint8_t iFunction, int32_t *prc) +{ + /* + * Find the session. + */ + const RTPROCESS Process = RTProcSelf(); + const unsigned iHash = SESSION_HASH(sfn); + PVBOXGUESTSESSION pSession; + + RTSpinlockAcquire(g_Spinlock); + pSession = g_apSessionHashTab[iHash]; + if (pSession && pSession->Process != Process) + { + do pSession = pSession->pNextHash; + while ( pSession + && ( pSession->sfn != sfn + || pSession->Process != Process)); + } + RTSpinlockRelease(g_Spinlock); + if (RT_UNLIKELY(!pSession)) + { + Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process)); + return VERR_INVALID_PARAMETER; + } + + /* + * Dispatch the fast IOCtl. + */ + *prc = VGDrvCommonIoCtlFast(iFunction, &g_DevExt, pSession); + return 0; +} + + +/** + * 32-bit IDC service routine. + * + * @returns VBox status code. + * @param u32Session The session handle (PVBOXGUESTSESSION). + * @param iFunction The requested function. + * @param pReqHdr The input/output data buffer. The caller + * ensures that this cannot be swapped out, or that + * it's acceptable to take a page in fault in the + * current context. If the request doesn't take + * input or produces output, apssing NULL is okay. + * @param cbReq The size of the data buffer. + * + * @remark This is called from the 16-bit thunker as well as directly from the 32-bit clients. + */ +DECLASM(int) VGDrvOS2IDCService(uint32_t u32Session, unsigned iFunction, PVBGLREQHDR pReqHdr, size_t cbReq) +{ + PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)u32Session; + AssertPtrReturn(pSession, VERR_INVALID_POINTER); + AssertMsgReturn(pSession->sfn == 0xffff, ("%RX16\n", pSession->sfn), VERR_INVALID_HANDLE); + AssertMsgReturn(pSession->pDevExt == &g_DevExt, ("%p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE); + + return VGDrvCommonIoCtl(iFunction, &g_DevExt, pSession, pReqHdr, cbReq); +} + + +/** + * Worker for VBoxGuestOS2IDC, it creates the kernel session. + * + * @returns Pointer to the session. + */ +DECLASM(PVBOXGUESTSESSION) vgdrvOS2IDCConnect(void) +{ + PVBOXGUESTSESSION pSession; + int rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession); + if (RT_SUCCESS(rc)) + { + pSession->sfn = 0xffff; + return pSession; + } + return NULL; +} + + +DECLASM(int) vgdrvOS2IOCtl(uint16_t sfn, uint8_t iCat, uint8_t iFunction, void *pvParm, void *pvData, + uint16_t *pcbParm, uint16_t *pcbData) +{ + /* + * Find the session. + */ + const RTPROCESS Process = RTProcSelf(); + const unsigned iHash = SESSION_HASH(sfn); + PVBOXGUESTSESSION pSession; + + RTSpinlockAcquire(g_Spinlock); + pSession = g_apSessionHashTab[iHash]; + if (pSession && pSession->Process != Process) + { + do pSession = pSession->pNextHash; + while ( pSession + && ( pSession->sfn != sfn + || pSession->Process != Process)); + } + RTSpinlockRelease(g_Spinlock); + if (!pSession) + { + Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process)); + return VERR_INVALID_PARAMETER; + } + + /* + * Verify the category and dispatch the IOCtl. + * + * The IOCtl call uses the parameter buffer as generic data input/output + * buffer similar to the one unix ioctl buffer argument. While the data + * buffer is not used. + */ + if (RT_LIKELY(iCat == VBGL_IOCTL_CATEGORY)) + { + Log(("vgdrvOS2IOCtl: pSession=%p iFunction=%#x pvParm=%p pvData=%p *pcbParm=%d *pcbData=%d\n", pSession, iFunction, pvParm, pvData, *pcbParm, *pcbData)); + if ( pvParm + && *pcbParm >= sizeof(VBGLREQHDR) + && *pcbData == 0) + { + /* + * Lock the buffer. + */ + KernVMLock_t ParmLock; + int32_t rc = KernVMLock(VMDHL_WRITE, pvParm, *pcbParm, &ParmLock, (KernPageList_t *)-1, NULL); + if (rc == 0) + { + /* + * Process the IOCtl. + */ + PVBGLREQHDR pReqHdr = (PVBGLREQHDR)pvParm; + rc = VGDrvCommonIoCtl(iFunction, &g_DevExt, pSession, pReqHdr, *pcbParm); + + /* + * Unlock the buffer. + */ + *pcbParm = RT_SUCCESS(rc) ? pReqHdr->cbOut : sizeof(*pReqHdr); + int rc2 = KernVMUnlock(&ParmLock); + AssertMsg(rc2 == 0, ("rc2=%d\n", rc2)); NOREF(rc2); + + Log2(("vgdrvOS2IOCtl: returns %d\n", rc)); + return rc; + } + AssertMsgFailed(("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pvParm, *pcbParm, &ParmLock, rc)); + return VERR_LOCK_FAILED; + } + Log2(("vgdrvOS2IOCtl: returns VERR_INVALID_PARAMETER (iFunction=%#x)\n", iFunction)); + return VERR_INVALID_PARAMETER; + } + return VERR_NOT_SUPPORTED; +} + + +/** + * 32-bit ISR, called by 16-bit assembly thunker in VBoxGuestA-os2.asm. + * + * @returns true if it's our interrupt, false it isn't. + */ +DECLASM(bool) vgdrvOS2ISR(void) +{ + Log(("vgdrvOS2ISR\n")); + + return VGDrvCommonISR(&g_DevExt); +} + + +void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt) +{ + /* No polling on OS/2 */ + NOREF(pDevExt); +} + + +bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue) +{ + RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue); + return false; +} + + +#ifdef DEBUG_READ /** @todo figure out this one once and for all... */ + +/** + * Callback for writing to the log buffer. + * + * @returns number of bytes written. + * @param pvArg Unused. + * @param pachChars Pointer to an array of utf-8 characters. + * @param cbChars Number of bytes in the character array pointed to by pachChars. + */ +static DECLCALLBACK(size_t) vgdrvOS2LogOutput(void *pvArg, const char *pachChars, size_t cbChars) +{ + size_t cchWritten = 0; + while (cbChars-- > 0) + { + const uint16_t offLogHead = g_offLogHead; + const uint16_t offLogHeadNext = (offLogHead + 1) & (g_cchLogMax - 1); + if (offLogHeadNext == g_offLogTail) + break; /* no */ + g_szLog[offLogHead] = *pachChars++; + g_offLogHead = offLogHeadNext; + cchWritten++; + } + return cchWritten; +} + + +int SUPR0Printf(const char *pszFormat, ...) +{ + va_list va; + +#if 0 //def DEBUG_bird + va_start(va, pszFormat); + RTLogComPrintfV(pszFormat, va); + va_end(va); +#endif + + va_start(va, pszFormat); + int cch = RTLogFormatV(vgdrvOS2LogOutput, NULL, pszFormat, va); + va_end(va); + + return cch; +} + +#endif /* DEBUG_READ */ + |