[3657] | 1 | /* $Id: VBoxGuest-os2.cpp 100274 2023-06-23 18:44:41Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * VBoxGuest - OS/2 specifics.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2007-2023 Oracle and/or its affiliates.
|
---|
[3657] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[3657] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[69308] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[69308] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[69498] | 35 | * ---------------------------------------------------------------------------
|
---|
[3657] | 36 | * This code is based on:
|
---|
| 37 | *
|
---|
| 38 | * VBoxDrv - OS/2 specifics.
|
---|
| 39 | *
|
---|
[48665] | 40 | * Copyright (c) 2007-2012 knut st. osmundsen <bird-src-spam@anduin.net>
|
---|
[3657] | 41 | *
|
---|
| 42 | * Permission is hereby granted, free of charge, to any person
|
---|
| 43 | * obtaining a copy of this software and associated documentation
|
---|
| 44 | * files (the "Software"), to deal in the Software without
|
---|
| 45 | * restriction, including without limitation the rights to use,
|
---|
| 46 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
|
---|
| 47 | * copies of the Software, and to permit persons to whom the
|
---|
| 48 | * Software is furnished to do so, subject to the following
|
---|
| 49 | * conditions:
|
---|
| 50 | *
|
---|
| 51 | * The above copyright notice and this permission notice shall be
|
---|
| 52 | * included in all copies or substantial portions of the Software.
|
---|
| 53 | *
|
---|
| 54 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
---|
| 55 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
---|
| 56 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
---|
| 57 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
---|
| 58 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
---|
| 59 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
---|
| 60 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
---|
| 61 | * OTHER DEALINGS IN THE SOFTWARE.
|
---|
| 62 | */
|
---|
| 63 |
|
---|
| 64 |
|
---|
[57358] | 65 | /*********************************************************************************************************************************
|
---|
| 66 | * Header Files *
|
---|
| 67 | *********************************************************************************************************************************/
|
---|
[3657] | 68 | #include <os2ddk/bsekee.h>
|
---|
| 69 |
|
---|
| 70 | #include "VBoxGuestInternal.h"
|
---|
| 71 | #include <VBox/version.h>
|
---|
[68570] | 72 | #include <iprt/assert.h>
|
---|
[76437] | 73 | #include <iprt/err.h>
|
---|
[3657] | 74 | #include <iprt/initterm.h>
|
---|
| 75 | #include <iprt/log.h>
|
---|
[6654] | 76 | #include <iprt/memobj.h>
|
---|
| 77 | #include <iprt/mem.h>
|
---|
| 78 | #include <iprt/param.h>
|
---|
[68570] | 79 | #include <iprt/process.h>
|
---|
| 80 | #include <iprt/spinlock.h>
|
---|
| 81 | #include <iprt/string.h>
|
---|
[3657] | 82 |
|
---|
| 83 |
|
---|
[57358] | 84 | /*********************************************************************************************************************************
|
---|
| 85 | * Global Variables *
|
---|
| 86 | *********************************************************************************************************************************/
|
---|
[3657] | 87 | /**
|
---|
| 88 | * Device extention & session data association structure.
|
---|
| 89 | */
|
---|
| 90 | static VBOXGUESTDEVEXT g_DevExt;
|
---|
[6032] | 91 | /** The memory object for the MMIO memory. */
|
---|
| 92 | static RTR0MEMOBJ g_MemObjMMIO = NIL_RTR0MEMOBJ;
|
---|
| 93 | /** The memory mapping object the MMIO memory. */
|
---|
| 94 | static RTR0MEMOBJ g_MemMapMMIO = NIL_RTR0MEMOBJ;
|
---|
| 95 |
|
---|
[3657] | 96 | /** Spinlock protecting g_apSessionHashTab. */
|
---|
| 97 | static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
|
---|
| 98 | /** Hash table */
|
---|
| 99 | static PVBOXGUESTSESSION g_apSessionHashTab[19];
|
---|
| 100 | /** Calculates the index into g_apSessionHashTab.*/
|
---|
| 101 | #define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
|
---|
| 102 |
|
---|
[20374] | 103 | RT_C_DECLS_BEGIN
|
---|
[3657] | 104 | /* Defined in VBoxGuestA-os2.asm */
|
---|
| 105 | extern uint32_t g_PhysMMIOBase;
|
---|
| 106 | extern uint32_t g_cbMMIO; /* 0 currently not set. */
|
---|
| 107 | extern uint16_t g_IOPortBase;
|
---|
| 108 | extern uint8_t g_bInterruptLine;
|
---|
| 109 | extern uint8_t g_bPciBusNo;
|
---|
| 110 | extern uint8_t g_bPciDevFunNo;
|
---|
| 111 | extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16;
|
---|
| 112 | extern RTFAR16 g_fpfnVBoxGuestOs2IDCService16Asm;
|
---|
| 113 | #ifdef DEBUG_READ
|
---|
| 114 | /* (debugging) */
|
---|
| 115 | extern uint16_t g_offLogHead;
|
---|
| 116 | extern uint16_t volatile g_offLogTail;
|
---|
| 117 | extern uint16_t const g_cchLogMax;
|
---|
| 118 | extern char g_szLog[];
|
---|
| 119 | #endif
|
---|
| 120 | /* (init only:) */
|
---|
| 121 | extern char g_szInitText[];
|
---|
| 122 | extern uint16_t g_cchInitText;
|
---|
| 123 | extern uint16_t g_cchInitTextMax;
|
---|
[20374] | 124 | RT_C_DECLS_END
|
---|
[3657] | 125 |
|
---|
| 126 |
|
---|
[57358] | 127 | /*********************************************************************************************************************************
|
---|
| 128 | * Internal Functions *
|
---|
| 129 | *********************************************************************************************************************************/
|
---|
[58113] | 130 | static int vgdrvOS2MapMemory(void);
|
---|
| 131 | static VBOXOSTYPE vgdrvOS2DetectVersion(void);
|
---|
[3657] | 132 |
|
---|
| 133 | /* in VBoxGuestA-os2.asm */
|
---|
[58113] | 134 | DECLASM(int) vgdrvOS2DevHlpSetIRQ(uint8_t bIRQ);
|
---|
[3657] | 135 |
|
---|
| 136 |
|
---|
| 137 | /**
|
---|
| 138 | * 32-bit Ring-0 initialization.
|
---|
[6032] | 139 | *
|
---|
[3657] | 140 | * This is called from VBoxGuestA-os2.asm upon the first open call to the vboxgst$ device.
|
---|
| 141 | *
|
---|
| 142 | * @returns 0 on success, non-zero on failure.
|
---|
| 143 | * @param pszArgs Pointer to the device arguments.
|
---|
| 144 | */
|
---|
[58113] | 145 | DECLASM(int) vgdrvOS2Init(const char *pszArgs)
|
---|
[3657] | 146 | {
|
---|
[75552] | 147 | //Log(("vgdrvOS2Init: pszArgs='%s' MMIO=0x%RX32 IOPort=0x%RX16 Int=%#x Bus=%#x Dev=%#x Fun=%d\n",
|
---|
| 148 | // pszArgs, g_PhysMMIOBase, g_IOPortBase, g_bInterruptLine, g_bPciBusNo, g_bPciDevFunNo >> 3, g_bPciDevFunNo & 7));
|
---|
[3657] | 149 |
|
---|
| 150 | /*
|
---|
| 151 | * Initialize the runtime.
|
---|
| 152 | */
|
---|
| 153 | int rc = RTR0Init(0);
|
---|
| 154 | if (RT_SUCCESS(rc))
|
---|
| 155 | {
|
---|
| 156 | /*
|
---|
[76732] | 157 | * Process the command line.
|
---|
[3657] | 158 | */
|
---|
| 159 | bool fVerbose = true;
|
---|
[76732] | 160 | if (pszArgs)
|
---|
| 161 | {
|
---|
| 162 | char ch;
|
---|
| 163 | while ((ch = *pszArgs++) != '\0')
|
---|
| 164 | if (ch == '-' || ch == '/')
|
---|
| 165 | {
|
---|
| 166 | ch = *pszArgs++;
|
---|
| 167 | if (ch == 'Q' || ch == 'q')
|
---|
| 168 | fVerbose = false;
|
---|
| 169 | else if (ch == 'V' || ch == 'v')
|
---|
| 170 | fVerbose = true;
|
---|
| 171 | else if (ch == '\0')
|
---|
| 172 | break;
|
---|
| 173 | /*else: ignore stuff we don't know what is */
|
---|
| 174 | }
|
---|
| 175 | /* else: skip spaces and unknown stuff */
|
---|
| 176 | }
|
---|
[3657] | 177 |
|
---|
| 178 | /*
|
---|
[6032] | 179 | * Map the MMIO memory if found.
|
---|
[3657] | 180 | */
|
---|
[58113] | 181 | rc = vgdrvOS2MapMemory();
|
---|
[3657] | 182 | if (RT_SUCCESS(rc))
|
---|
| 183 | {
|
---|
| 184 | /*
|
---|
[6032] | 185 | * Initialize the device extension.
|
---|
[3657] | 186 | */
|
---|
[6032] | 187 | if (g_MemMapMMIO != NIL_RTR0MEMOBJ)
|
---|
[58053] | 188 | rc = VGDrvCommonInitDevExt(&g_DevExt, g_IOPortBase,
|
---|
[100267] | 189 | NULL /*pvMmioReq*/,
|
---|
[58053] | 190 | RTR0MemObjAddress(g_MemMapMMIO),
|
---|
| 191 | RTR0MemObjSize(g_MemMapMMIO),
|
---|
[58113] | 192 | vgdrvOS2DetectVersion(),
|
---|
[58053] | 193 | 0);
|
---|
[6032] | 194 | else
|
---|
[100274] | 195 | rc = VGDrvCommonInitDevExt(&g_DevExt, g_IOPortBase, NULL /*pvMmioReq*/, NULL, 0, vgdrvOS2DetectVersion(), 0);
|
---|
[3657] | 196 | if (RT_SUCCESS(rc))
|
---|
| 197 | {
|
---|
| 198 | /*
|
---|
[6032] | 199 | * Initialize the session hash table.
|
---|
[3657] | 200 | */
|
---|
[40806] | 201 | rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxGuestOS2");
|
---|
[3657] | 202 | if (RT_SUCCESS(rc))
|
---|
| 203 | {
|
---|
| 204 | /*
|
---|
[6032] | 205 | * Configure the interrupt handler.
|
---|
[3657] | 206 | */
|
---|
[6032] | 207 | if (g_bInterruptLine)
|
---|
[3657] | 208 | {
|
---|
[58113] | 209 | rc = vgdrvOS2DevHlpSetIRQ(g_bInterruptLine);
|
---|
[6032] | 210 | if (rc)
|
---|
| 211 | {
|
---|
[58113] | 212 | Log(("vgdrvOS2DevHlpSetIRQ(%d) -> %d\n", g_bInterruptLine, rc));
|
---|
[6032] | 213 | rc = RTErrConvertFromOS2(rc);
|
---|
| 214 | }
|
---|
[3657] | 215 | }
|
---|
[6032] | 216 | if (RT_SUCCESS(rc))
|
---|
| 217 | {
|
---|
| 218 | /*
|
---|
[70085] | 219 | * Read host configuration.
|
---|
| 220 | */
|
---|
| 221 | VGDrvCommonProcessOptionsFromHost(&g_DevExt);
|
---|
| 222 |
|
---|
| 223 | /*
|
---|
[6032] | 224 | * Success
|
---|
| 225 | */
|
---|
| 226 | if (fVerbose)
|
---|
| 227 | {
|
---|
| 228 | strcpy(&g_szInitText[0],
|
---|
| 229 | "\r\n"
|
---|
| 230 | "VirtualBox Guest Additions Driver for OS/2 version " VBOX_VERSION_STRING "\r\n"
|
---|
[54521] | 231 | "Copyright (C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\r\n");
|
---|
[6032] | 232 | g_cchInitText = strlen(&g_szInitText[0]);
|
---|
| 233 | }
|
---|
[58113] | 234 | Log(("vgdrvOS2Init: Successfully loaded\n%s", g_szInitText));
|
---|
[6032] | 235 | return VINF_SUCCESS;
|
---|
| 236 | }
|
---|
| 237 |
|
---|
[13837] | 238 | g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: SetIrq failed for IRQ %#d, rc=%Rrc\n",
|
---|
[6032] | 239 | g_bInterruptLine, rc);
|
---|
[3657] | 240 | }
|
---|
[6032] | 241 | else
|
---|
[13837] | 242 | g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTSpinlockCreate failed, rc=%Rrc\n", rc);
|
---|
[58053] | 243 | VGDrvCommonDeleteDevExt(&g_DevExt);
|
---|
[3657] | 244 | }
|
---|
| 245 | else
|
---|
[58113] | 246 | g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: vgdrvOS2InitDevExt failed, rc=%Rrc\n", rc);
|
---|
[6032] | 247 |
|
---|
[6654] | 248 | int rc2 = RTR0MemObjFree(g_MemObjMMIO, true /* fFreeMappings */); AssertRC(rc2);
|
---|
[6032] | 249 | g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ;
|
---|
[3657] | 250 | }
|
---|
| 251 | else
|
---|
[13837] | 252 | g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: VBoxGuestOS2MapMMIO failed, rc=%Rrc\n", rc);
|
---|
[3657] | 253 | RTR0Term();
|
---|
| 254 | }
|
---|
| 255 | else
|
---|
[13837] | 256 | g_cchInitText = RTStrPrintf(&g_szInitText[0], g_cchInitTextMax, "VBoxGuest.sys: RTR0Init failed, rc=%Rrc\n", rc);
|
---|
[3657] | 257 |
|
---|
[58113] | 258 | RTLogBackdoorPrintf("vgdrvOS2Init: failed rc=%Rrc - %s", rc, &g_szInitText[0]);
|
---|
[3657] | 259 | return rc;
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 |
|
---|
| 263 | /**
|
---|
[6032] | 264 | * Maps the VMMDev memory.
|
---|
| 265 | *
|
---|
| 266 | * @returns VBox status code.
|
---|
| 267 | * @retval VERR_VERSION_MISMATCH The VMMDev memory didn't meet our expectations.
|
---|
| 268 | */
|
---|
[58113] | 269 | static int vgdrvOS2MapMemory(void)
|
---|
[6032] | 270 | {
|
---|
| 271 | const RTCCPHYS PhysMMIOBase = g_PhysMMIOBase;
|
---|
| 272 |
|
---|
| 273 | /*
|
---|
| 274 | * Did we find any MMIO region (0 or NIL)?
|
---|
| 275 | */
|
---|
| 276 | if ( !PhysMMIOBase
|
---|
| 277 | || PhysMMIOBase == NIL_RTCCPHYS)
|
---|
| 278 | {
|
---|
| 279 | Assert(g_MemMapMMIO != NIL_RTR0MEMOBJ);
|
---|
| 280 | return VINF_SUCCESS;
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | /*
|
---|
| 284 | * Create a physical memory object for it.
|
---|
| 285 | *
|
---|
| 286 | * Since we don't know the actual size (OS/2 doesn't at least), we make
|
---|
| 287 | * a qualified guess using the VMMDEV_RAM_SIZE.
|
---|
| 288 | */
|
---|
| 289 | size_t cb = RT_ALIGN_Z(VMMDEV_RAM_SIZE, PAGE_SIZE);
|
---|
[28777] | 290 | int rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE);
|
---|
[6032] | 291 | if (RT_FAILURE(rc))
|
---|
| 292 | {
|
---|
| 293 | cb = _4K;
|
---|
[28777] | 294 | rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE);
|
---|
[6032] | 295 | }
|
---|
| 296 | if (RT_FAILURE(rc))
|
---|
| 297 | {
|
---|
[58113] | 298 | Log(("vgdrvOS2MapMemory: RTR0MemObjEnterPhys(,%RCp,%zx) -> %Rrc\n", PhysMMIOBase, cb, rc));
|
---|
[6032] | 299 | return rc;
|
---|
| 300 | }
|
---|
| 301 |
|
---|
| 302 | /*
|
---|
| 303 | * Map the object into kernel space.
|
---|
| 304 | *
|
---|
| 305 | * We want a normal mapping with normal caching, which good in two ways. First
|
---|
| 306 | * since the API doesn't have any flags indicating how the mapping should be cached.
|
---|
| 307 | * And second, because PGM doesn't necessarily respect the cache/writethru bits
|
---|
| 308 | * anyway for normal RAM.
|
---|
| 309 | */
|
---|
[58113] | 310 | rc = RTR0MemObjMapKernel(&g_MemMapMMIO, g_MemObjMMIO, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
[6032] | 311 | if (RT_SUCCESS(rc))
|
---|
| 312 | {
|
---|
| 313 | /*
|
---|
| 314 | * Validate the VMM memory.
|
---|
| 315 | */
|
---|
| 316 | VMMDevMemory *pVMMDev = (VMMDevMemory *)RTR0MemObjAddress(g_MemMapMMIO);
|
---|
| 317 | Assert(pVMMDev);
|
---|
| 318 | if ( pVMMDev->u32Version == VMMDEV_MEMORY_VERSION
|
---|
| 319 | && pVMMDev->u32Size >= 32 /* just for checking sanity */)
|
---|
| 320 | {
|
---|
| 321 | /*
|
---|
[14297] | 322 | * Did we hit the correct size? If not we'll have to
|
---|
[6032] | 323 | * redo the mapping using the correct size.
|
---|
| 324 | */
|
---|
| 325 | if (RT_ALIGN_32(pVMMDev->u32Size, PAGE_SIZE) == cb)
|
---|
| 326 | return VINF_SUCCESS;
|
---|
| 327 |
|
---|
[58113] | 328 | Log(("vgdrvOS2MapMemory: Actual size %#RX32 (tried %#zx)\n", pVMMDev->u32Size, cb));
|
---|
[6032] | 329 | cb = RT_ALIGN_32(pVMMDev->u32Size, PAGE_SIZE);
|
---|
| 330 |
|
---|
| 331 | rc = RTR0MemObjFree(g_MemObjMMIO, true); AssertRC(rc);
|
---|
| 332 | g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ;
|
---|
| 333 |
|
---|
[28777] | 334 | rc = RTR0MemObjEnterPhys(&g_MemObjMMIO, PhysMMIOBase, cb, RTMEM_CACHE_POLICY_DONT_CARE);
|
---|
[6032] | 335 | if (RT_SUCCESS(rc))
|
---|
| 336 | {
|
---|
[58113] | 337 | rc = RTR0MemObjMapKernel(&g_MemMapMMIO, g_MemObjMMIO, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
|
---|
[6032] | 338 | if (RT_SUCCESS(rc))
|
---|
| 339 | return VINF_SUCCESS;
|
---|
| 340 |
|
---|
[58113] | 341 | Log(("vgdrvOS2MapMemory: RTR0MemObjMapKernel [%RCp,%zx] -> %Rrc (2nd)\n", PhysMMIOBase, cb, rc));
|
---|
[6032] | 342 | }
|
---|
| 343 | else
|
---|
[58113] | 344 | Log(("vgdrvOS2MapMemory: RTR0MemObjEnterPhys(,%RCp,%zx) -> %Rrc (2nd)\n", PhysMMIOBase, cb, rc));
|
---|
[6032] | 345 | }
|
---|
| 346 | else
|
---|
| 347 | {
|
---|
| 348 | rc = VERR_VERSION_MISMATCH;
|
---|
[58113] | 349 | LogRel(("vgdrvOS2MapMemory: Bogus VMMDev memory; u32Version=%RX32 (expected %RX32) u32Size=%RX32\n",
|
---|
[6032] | 350 | pVMMDev->u32Version, VMMDEV_MEMORY_VERSION, pVMMDev->u32Size));
|
---|
| 351 | }
|
---|
| 352 | }
|
---|
| 353 | else
|
---|
[58113] | 354 | Log(("vgdrvOS2MapMemory: RTR0MemObjMapKernel [%RCp,%zx] -> %Rrc\n", PhysMMIOBase, cb, rc));
|
---|
[6032] | 355 |
|
---|
| 356 | int rc2 = RTR0MemObjFree(g_MemObjMMIO, true /* fFreeMappings */); AssertRC(rc2);
|
---|
| 357 | g_MemObjMMIO = g_MemMapMMIO = NIL_RTR0MEMOBJ;
|
---|
| 358 | return rc;
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 |
|
---|
| 362 | /**
|
---|
[58113] | 363 | * Called fromn vgdrvOS2Init to determine which OS/2 version this is.
|
---|
[6032] | 364 | *
|
---|
[3657] | 365 | * @returns VBox OS/2 type.
|
---|
| 366 | */
|
---|
[58113] | 367 | static VBOXOSTYPE vgdrvOS2DetectVersion(void)
|
---|
[3657] | 368 | {
|
---|
[7233] | 369 | VBOXOSTYPE enmOSType = VBOXOSTYPE_OS2;
|
---|
[3657] | 370 |
|
---|
| 371 | #if 0 /** @todo dig up the version stuff from GIS later and verify that the numbers are actually decimal. */
|
---|
| 372 | unsigned uMajor, uMinor;
|
---|
| 373 | if (uMajor == 2)
|
---|
| 374 | {
|
---|
| 375 | if (uMinor >= 30 && uMinor < 40)
|
---|
[7233] | 376 | enmOSType = VBOXOSTYPE_OS2Warp3;
|
---|
[3657] | 377 | else if (uMinor >= 40 && uMinor < 45)
|
---|
[7233] | 378 | enmOSType = VBOXOSTYPE_OS2Warp4;
|
---|
[3657] | 379 | else if (uMinor >= 45 && uMinor < 50)
|
---|
[7233] | 380 | enmOSType = VBOXOSTYPE_OS2Warp45;
|
---|
[3657] | 381 | }
|
---|
[6032] | 382 | #endif
|
---|
[3657] | 383 | return enmOSType;
|
---|
| 384 | }
|
---|
| 385 |
|
---|
| 386 |
|
---|
[58113] | 387 | DECLASM(int) vgdrvOS2Open(uint16_t sfn)
|
---|
[3657] | 388 | {
|
---|
| 389 | int rc;
|
---|
| 390 | PVBOXGUESTSESSION pSession;
|
---|
| 391 |
|
---|
| 392 | /*
|
---|
| 393 | * Create a new session.
|
---|
| 394 | */
|
---|
[75779] | 395 | uint32_t fRequestor = VMMDEV_REQUESTOR_USERMODE
|
---|
| 396 | | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN
|
---|
| 397 | | VMMDEV_REQUESTOR_USR_ROOT /* everyone is root on OS/2 */
|
---|
| 398 | | VMMDEV_REQUESTOR_GRP_WHEEL /* and their admins */
|
---|
| 399 | | VMMDEV_REQUESTOR_NO_USER_DEVICE /** @todo implement /dev/vboxuser? */
|
---|
| 400 | | VMMDEV_REQUESTOR_CON_DONT_KNOW; /** @todo check screen group/whatever of process to see if console */
|
---|
| 401 | rc = VGDrvCommonCreateUserSession(&g_DevExt, fRequestor, &pSession);
|
---|
[3657] | 402 | if (RT_SUCCESS(rc))
|
---|
| 403 | {
|
---|
| 404 | pSession->sfn = sfn;
|
---|
| 405 |
|
---|
| 406 | /*
|
---|
| 407 | * Insert it into the hash table.
|
---|
| 408 | */
|
---|
| 409 | unsigned iHash = SESSION_HASH(sfn);
|
---|
[40806] | 410 | RTSpinlockAcquire(g_Spinlock);
|
---|
[3657] | 411 | pSession->pNextHash = g_apSessionHashTab[iHash];
|
---|
| 412 | g_apSessionHashTab[iHash] = pSession;
|
---|
[52618] | 413 | RTSpinlockRelease(g_Spinlock);
|
---|
[3657] | 414 | }
|
---|
| 415 |
|
---|
[58113] | 416 | Log(("vgdrvOS2Open: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
|
---|
[3657] | 417 | return rc;
|
---|
| 418 | }
|
---|
| 419 |
|
---|
| 420 |
|
---|
[58113] | 421 | DECLASM(int) vgdrvOS2Close(uint16_t sfn)
|
---|
[3657] | 422 | {
|
---|
[58113] | 423 | Log(("vgdrvOS2Close: pid=%d sfn=%d\n", (int)RTProcSelf(), sfn));
|
---|
[3657] | 424 |
|
---|
| 425 | /*
|
---|
| 426 | * Remove from the hash table.
|
---|
| 427 | */
|
---|
| 428 | PVBOXGUESTSESSION pSession;
|
---|
| 429 | const RTPROCESS Process = RTProcSelf();
|
---|
| 430 | const unsigned iHash = SESSION_HASH(sfn);
|
---|
[40806] | 431 | RTSpinlockAcquire(g_Spinlock);
|
---|
[3657] | 432 |
|
---|
| 433 | pSession = g_apSessionHashTab[iHash];
|
---|
| 434 | if (pSession)
|
---|
| 435 | {
|
---|
| 436 | if ( pSession->sfn == sfn
|
---|
| 437 | && pSession->Process == Process)
|
---|
| 438 | {
|
---|
| 439 | g_apSessionHashTab[iHash] = pSession->pNextHash;
|
---|
| 440 | pSession->pNextHash = NULL;
|
---|
| 441 | }
|
---|
| 442 | else
|
---|
| 443 | {
|
---|
| 444 | PVBOXGUESTSESSION pPrev = pSession;
|
---|
| 445 | pSession = pSession->pNextHash;
|
---|
| 446 | while (pSession)
|
---|
| 447 | {
|
---|
| 448 | if ( pSession->sfn == sfn
|
---|
| 449 | && pSession->Process == Process)
|
---|
| 450 | {
|
---|
| 451 | pPrev->pNextHash = pSession->pNextHash;
|
---|
| 452 | pSession->pNextHash = NULL;
|
---|
| 453 | break;
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | /* next */
|
---|
| 457 | pPrev = pSession;
|
---|
| 458 | pSession = pSession->pNextHash;
|
---|
| 459 | }
|
---|
| 460 | }
|
---|
| 461 | }
|
---|
[52618] | 462 | RTSpinlockRelease(g_Spinlock);
|
---|
[3657] | 463 | if (!pSession)
|
---|
| 464 | {
|
---|
| 465 | Log(("VBoxGuestIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d sfn=%d\n", (int)Process, sfn));
|
---|
| 466 | return VERR_INVALID_PARAMETER;
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | /*
|
---|
| 470 | * Close the session.
|
---|
| 471 | */
|
---|
[58053] | 472 | VGDrvCommonCloseSession(&g_DevExt, pSession);
|
---|
[3657] | 473 | return 0;
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 |
|
---|
[58113] | 477 | DECLASM(int) vgdrvOS2IOCtlFast(uint16_t sfn, uint8_t iFunction, int32_t *prc)
|
---|
[3657] | 478 | {
|
---|
| 479 | /*
|
---|
| 480 | * Find the session.
|
---|
| 481 | */
|
---|
| 482 | const RTPROCESS Process = RTProcSelf();
|
---|
| 483 | const unsigned iHash = SESSION_HASH(sfn);
|
---|
| 484 | PVBOXGUESTSESSION pSession;
|
---|
| 485 |
|
---|
[40806] | 486 | RTSpinlockAcquire(g_Spinlock);
|
---|
[3657] | 487 | pSession = g_apSessionHashTab[iHash];
|
---|
| 488 | if (pSession && pSession->Process != Process)
|
---|
| 489 | {
|
---|
| 490 | do pSession = pSession->pNextHash;
|
---|
| 491 | while ( pSession
|
---|
| 492 | && ( pSession->sfn != sfn
|
---|
| 493 | || pSession->Process != Process));
|
---|
| 494 | }
|
---|
[52618] | 495 | RTSpinlockRelease(g_Spinlock);
|
---|
[3657] | 496 | if (RT_UNLIKELY(!pSession))
|
---|
| 497 | {
|
---|
| 498 | Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
|
---|
| 499 | return VERR_INVALID_PARAMETER;
|
---|
| 500 | }
|
---|
| 501 |
|
---|
| 502 | /*
|
---|
| 503 | * Dispatch the fast IOCtl.
|
---|
| 504 | */
|
---|
[58053] | 505 | *prc = VGDrvCommonIoCtlFast(iFunction, &g_DevExt, pSession);
|
---|
[3657] | 506 | return 0;
|
---|
| 507 | }
|
---|
| 508 |
|
---|
| 509 |
|
---|
| 510 | /**
|
---|
| 511 | * 32-bit IDC service routine.
|
---|
[6032] | 512 | *
|
---|
[3657] | 513 | * @returns VBox status code.
|
---|
| 514 | * @param u32Session The session handle (PVBOXGUESTSESSION).
|
---|
| 515 | * @param iFunction The requested function.
|
---|
[68570] | 516 | * @param pReqHdr The input/output data buffer. The caller
|
---|
| 517 | * ensures that this cannot be swapped out, or that
|
---|
| 518 | * it's acceptable to take a page in fault in the
|
---|
| 519 | * current context. If the request doesn't take
|
---|
| 520 | * input or produces output, apssing NULL is okay.
|
---|
| 521 | * @param cbReq The size of the data buffer.
|
---|
[6032] | 522 | *
|
---|
[3657] | 523 | * @remark This is called from the 16-bit thunker as well as directly from the 32-bit clients.
|
---|
| 524 | */
|
---|
[68570] | 525 | DECLASM(int) VGDrvOS2IDCService(uint32_t u32Session, unsigned iFunction, PVBGLREQHDR pReqHdr, size_t cbReq)
|
---|
[3657] | 526 | {
|
---|
| 527 | PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)u32Session;
|
---|
| 528 | AssertPtrReturn(pSession, VERR_INVALID_POINTER);
|
---|
| 529 | AssertMsgReturn(pSession->sfn == 0xffff, ("%RX16\n", pSession->sfn), VERR_INVALID_HANDLE);
|
---|
| 530 | AssertMsgReturn(pSession->pDevExt == &g_DevExt, ("%p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
|
---|
| 531 |
|
---|
[68570] | 532 | return VGDrvCommonIoCtl(iFunction, &g_DevExt, pSession, pReqHdr, cbReq);
|
---|
[3657] | 533 | }
|
---|
| 534 |
|
---|
| 535 |
|
---|
| 536 | /**
|
---|
| 537 | * Worker for VBoxGuestOS2IDC, it creates the kernel session.
|
---|
[6032] | 538 | *
|
---|
[3657] | 539 | * @returns Pointer to the session.
|
---|
| 540 | */
|
---|
[58113] | 541 | DECLASM(PVBOXGUESTSESSION) vgdrvOS2IDCConnect(void)
|
---|
[3657] | 542 | {
|
---|
| 543 | PVBOXGUESTSESSION pSession;
|
---|
[58053] | 544 | int rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
|
---|
[3657] | 545 | if (RT_SUCCESS(rc))
|
---|
| 546 | {
|
---|
| 547 | pSession->sfn = 0xffff;
|
---|
| 548 | return pSession;
|
---|
| 549 | }
|
---|
| 550 | return NULL;
|
---|
| 551 | }
|
---|
| 552 |
|
---|
| 553 |
|
---|
[58113] | 554 | DECLASM(int) vgdrvOS2IOCtl(uint16_t sfn, uint8_t iCat, uint8_t iFunction, void *pvParm, void *pvData,
|
---|
| 555 | uint16_t *pcbParm, uint16_t *pcbData)
|
---|
[3657] | 556 | {
|
---|
| 557 | /*
|
---|
| 558 | * Find the session.
|
---|
| 559 | */
|
---|
| 560 | const RTPROCESS Process = RTProcSelf();
|
---|
| 561 | const unsigned iHash = SESSION_HASH(sfn);
|
---|
| 562 | PVBOXGUESTSESSION pSession;
|
---|
| 563 |
|
---|
[40806] | 564 | RTSpinlockAcquire(g_Spinlock);
|
---|
[3657] | 565 | pSession = g_apSessionHashTab[iHash];
|
---|
| 566 | if (pSession && pSession->Process != Process)
|
---|
| 567 | {
|
---|
| 568 | do pSession = pSession->pNextHash;
|
---|
| 569 | while ( pSession
|
---|
| 570 | && ( pSession->sfn != sfn
|
---|
| 571 | || pSession->Process != Process));
|
---|
| 572 | }
|
---|
[52618] | 573 | RTSpinlockRelease(g_Spinlock);
|
---|
[3657] | 574 | if (!pSession)
|
---|
| 575 | {
|
---|
| 576 | Log(("VBoxGuestIoctl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d\n", (int)Process));
|
---|
| 577 | return VERR_INVALID_PARAMETER;
|
---|
| 578 | }
|
---|
| 579 |
|
---|
| 580 | /*
|
---|
| 581 | * Verify the category and dispatch the IOCtl.
|
---|
| 582 | *
|
---|
[6032] | 583 | * The IOCtl call uses the parameter buffer as generic data input/output
|
---|
[68550] | 584 | * buffer similar to the one unix ioctl buffer argument. While the data
|
---|
| 585 | * buffer is not used.
|
---|
[3657] | 586 | */
|
---|
[68550] | 587 | if (RT_LIKELY(iCat == VBGL_IOCTL_CATEGORY))
|
---|
[3657] | 588 | {
|
---|
[58113] | 589 | Log(("vgdrvOS2IOCtl: pSession=%p iFunction=%#x pvParm=%p pvData=%p *pcbParm=%d *pcbData=%d\n", pSession, iFunction, pvParm, pvData, *pcbParm, *pcbData));
|
---|
[68550] | 590 | if ( pvParm
|
---|
| 591 | && *pcbParm >= sizeof(VBGLREQHDR)
|
---|
| 592 | && *pcbData == 0)
|
---|
[3657] | 593 | {
|
---|
[68550] | 594 | /*
|
---|
| 595 | * Lock the buffer.
|
---|
| 596 | */
|
---|
| 597 | KernVMLock_t ParmLock;
|
---|
| 598 | int32_t rc = KernVMLock(VMDHL_WRITE, pvParm, *pcbParm, &ParmLock, (KernPageList_t *)-1, NULL);
|
---|
| 599 | if (rc == 0)
|
---|
[3657] | 600 | {
|
---|
[68550] | 601 | /*
|
---|
| 602 | * Process the IOCtl.
|
---|
| 603 | */
|
---|
| 604 | PVBGLREQHDR pReqHdr = (PVBGLREQHDR)pvParm;
|
---|
[68570] | 605 | rc = VGDrvCommonIoCtl(iFunction, &g_DevExt, pSession, pReqHdr, *pcbParm);
|
---|
[3657] | 606 |
|
---|
[68550] | 607 | /*
|
---|
| 608 | * Unlock the buffer.
|
---|
| 609 | */
|
---|
| 610 | *pcbParm = RT_SUCCESS(rc) ? pReqHdr->cbOut : sizeof(*pReqHdr);
|
---|
| 611 | int rc2 = KernVMUnlock(&ParmLock);
|
---|
| 612 | AssertMsg(rc2 == 0, ("rc2=%d\n", rc2)); NOREF(rc2);
|
---|
[3657] | 613 |
|
---|
[68550] | 614 | Log2(("vgdrvOS2IOCtl: returns %d\n", rc));
|
---|
| 615 | return rc;
|
---|
| 616 | }
|
---|
[68570] | 617 | AssertMsgFailed(("KernVMLock(VMDHL_WRITE, %p, %#x, &p, NULL, NULL) -> %d\n", pvParm, *pcbParm, &ParmLock, rc));
|
---|
[68550] | 618 | return VERR_LOCK_FAILED;
|
---|
[3657] | 619 | }
|
---|
[68550] | 620 | Log2(("vgdrvOS2IOCtl: returns VERR_INVALID_PARAMETER (iFunction=%#x)\n", iFunction));
|
---|
| 621 | return VERR_INVALID_PARAMETER;
|
---|
[3657] | 622 | }
|
---|
| 623 | return VERR_NOT_SUPPORTED;
|
---|
| 624 | }
|
---|
| 625 |
|
---|
| 626 |
|
---|
[6032] | 627 | /**
|
---|
[3657] | 628 | * 32-bit ISR, called by 16-bit assembly thunker in VBoxGuestA-os2.asm.
|
---|
[6032] | 629 | *
|
---|
[3657] | 630 | * @returns true if it's our interrupt, false it isn't.
|
---|
| 631 | */
|
---|
[58113] | 632 | DECLASM(bool) vgdrvOS2ISR(void)
|
---|
[3657] | 633 | {
|
---|
[58113] | 634 | Log(("vgdrvOS2ISR\n"));
|
---|
[3657] | 635 |
|
---|
[58053] | 636 | return VGDrvCommonISR(&g_DevExt);
|
---|
[3657] | 637 | }
|
---|
| 638 |
|
---|
| 639 |
|
---|
[58053] | 640 | void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
|
---|
[24287] | 641 | {
|
---|
| 642 | /* No polling on OS/2 */
|
---|
| 643 | NOREF(pDevExt);
|
---|
| 644 | }
|
---|
| 645 |
|
---|
| 646 |
|
---|
[70066] | 647 | bool VGDrvNativeProcessOption(PVBOXGUESTDEVEXT pDevExt, const char *pszName, const char *pszValue)
|
---|
| 648 | {
|
---|
| 649 | RT_NOREF(pDevExt); RT_NOREF(pszName); RT_NOREF(pszValue);
|
---|
| 650 | return false;
|
---|
| 651 | }
|
---|
| 652 |
|
---|
| 653 |
|
---|
[3657] | 654 | #ifdef DEBUG_READ /** @todo figure out this one once and for all... */
|
---|
| 655 |
|
---|
| 656 | /**
|
---|
| 657 | * Callback for writing to the log buffer.
|
---|
| 658 | *
|
---|
| 659 | * @returns number of bytes written.
|
---|
| 660 | * @param pvArg Unused.
|
---|
| 661 | * @param pachChars Pointer to an array of utf-8 characters.
|
---|
| 662 | * @param cbChars Number of bytes in the character array pointed to by pachChars.
|
---|
| 663 | */
|
---|
[58113] | 664 | static DECLCALLBACK(size_t) vgdrvOS2LogOutput(void *pvArg, const char *pachChars, size_t cbChars)
|
---|
[3657] | 665 | {
|
---|
| 666 | size_t cchWritten = 0;
|
---|
| 667 | while (cbChars-- > 0)
|
---|
| 668 | {
|
---|
| 669 | const uint16_t offLogHead = g_offLogHead;
|
---|
| 670 | const uint16_t offLogHeadNext = (offLogHead + 1) & (g_cchLogMax - 1);
|
---|
| 671 | if (offLogHeadNext == g_offLogTail)
|
---|
| 672 | break; /* no */
|
---|
| 673 | g_szLog[offLogHead] = *pachChars++;
|
---|
| 674 | g_offLogHead = offLogHeadNext;
|
---|
| 675 | cchWritten++;
|
---|
| 676 | }
|
---|
| 677 | return cchWritten;
|
---|
| 678 | }
|
---|
| 679 |
|
---|
| 680 |
|
---|
| 681 | int SUPR0Printf(const char *pszFormat, ...)
|
---|
| 682 | {
|
---|
| 683 | va_list va;
|
---|
| 684 |
|
---|
| 685 | #if 0 //def DEBUG_bird
|
---|
| 686 | va_start(va, pszFormat);
|
---|
| 687 | RTLogComPrintfV(pszFormat, va);
|
---|
| 688 | va_end(va);
|
---|
| 689 | #endif
|
---|
| 690 |
|
---|
| 691 | va_start(va, pszFormat);
|
---|
[58113] | 692 | int cch = RTLogFormatV(vgdrvOS2LogOutput, NULL, pszFormat, va);
|
---|
[3657] | 693 | va_end(va);
|
---|
| 694 |
|
---|
| 695 | return cch;
|
---|
| 696 | }
|
---|
| 697 |
|
---|
| 698 | #endif /* DEBUG_READ */
|
---|
| 699 |
|
---|