From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/HostDrivers/Support/solaris/Makefile.kup | 0 .../HostDrivers/Support/solaris/SUPDrv-solaris.c | 1347 ++++++++++++++++++++ .../HostDrivers/Support/solaris/SUPLib-solaris.cpp | 245 ++++ .../Support/solaris/SUPR0IdcClient-solaris.c | 66 + src/VBox/HostDrivers/Support/solaris/load.sh | 128 ++ src/VBox/HostDrivers/Support/solaris/vboxdrv.conf | 43 + 6 files changed, 1829 insertions(+) create mode 100644 src/VBox/HostDrivers/Support/solaris/Makefile.kup create mode 100644 src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c create mode 100644 src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp create mode 100644 src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c create mode 100755 src/VBox/HostDrivers/Support/solaris/load.sh create mode 100644 src/VBox/HostDrivers/Support/solaris/vboxdrv.conf (limited to 'src/VBox/HostDrivers/Support/solaris') diff --git a/src/VBox/HostDrivers/Support/solaris/Makefile.kup b/src/VBox/HostDrivers/Support/solaris/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c new file mode 100644 index 00000000..5e29b0a8 --- /dev/null +++ b/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c @@ -0,0 +1,1347 @@ +/* $Id: SUPDrv-solaris.c $ */ +/** @file + * VBoxDrv - The VirtualBox Support Driver - Solaris specifics. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_SUP_DRV +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */ + +#include "../SUPDrvInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dtrace/SUPDrv.h" + +extern caddr_t hat_kpm_pfn2va(pfn_t); /* Found in vm/hat.h on solaris 11.3, but not on older like 10u7. */ + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** The system device name. */ +#define DEVICE_NAME_SYS "vboxdrv" +/** The user device name. */ +#define DEVICE_NAME_USR "vboxdrvu" +/** The module description as seen in 'modinfo'. */ +#define DEVICE_DESC "VirtualBox HostDrv" +/** Maximum number of driver instances. */ +#define DEVICE_MAXINSTANCES 16 + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred); +static int VBoxDrvSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred); +static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred); +static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred); +static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal); + +static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd); +static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd); +static int VBoxDrvSolarisQuiesceNotNeeded(dev_info_t *pDip); + +static int VBoxSupDrvErr2SolarisErr(int rc); +static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int Cmd, int Mode, intptr_t pArgs); + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** + * cb_ops: for drivers that support char/block entry points + */ +static struct cb_ops g_VBoxDrvSolarisCbOps = +{ + VBoxDrvSolarisOpen, + VBoxDrvSolarisClose, + nodev, /* b strategy */ + nodev, /* b dump */ + nodev, /* b print */ + VBoxDrvSolarisRead, + VBoxDrvSolarisWrite, + VBoxDrvSolarisIOCtl, + nodev, /* c devmap */ + nodev, /* c mmap */ + nodev, /* c segmap */ + nochpoll, /* c poll */ + ddi_prop_op, /* property ops */ + NULL, /* streamtab */ + D_NEW | D_MP, /* compat. flag */ + CB_REV /* revision */ +}; + +/** + * dev_ops: for driver device operations + */ +static struct dev_ops g_VBoxDrvSolarisDevOps = +{ + DEVO_REV, /* driver build revision */ + 0, /* ref count */ + nulldev, /* get info */ + nulldev, /* identify */ + nulldev, /* probe */ + VBoxDrvSolarisAttach, + VBoxDrvSolarisDetach, + nodev, /* reset */ + &g_VBoxDrvSolarisCbOps, + (struct bus_ops *)0, + nodev, /* power */ + VBoxDrvSolarisQuiesceNotNeeded +}; + +/** + * modldrv: export driver specifics to the kernel + */ +static struct modldrv g_VBoxDrvSolarisModule = +{ + &mod_driverops, /* extern from kernel */ + DEVICE_DESC " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV), + &g_VBoxDrvSolarisDevOps +}; + +/** + * modlinkage: export install/remove/info to the kernel + */ +static struct modlinkage g_VBoxDrvSolarisModLinkage = +{ + MODREV_1, /* loadable module system revision */ + { + &g_VBoxDrvSolarisModule, + NULL /* terminate array of linkage structures */ + } +}; + +#ifndef USE_SESSION_HASH +/** + * State info for each open file handle. + */ +typedef struct +{ + /**< Pointer to the session data. */ + PSUPDRVSESSION pSession; +} vbox_devstate_t; +#else +/** State info. for each driver instance. */ +typedef struct +{ + dev_info_t *pDip; /* Device handle */ +} vbox_devstate_t; +#endif + +/** Opaque pointer to list of state */ +static void *g_pVBoxDrvSolarisState; + +/** Device extention & session data association structure */ +static SUPDRVDEVEXT g_DevExt; + +/** Hash table */ +static PSUPDRVSESSION g_apSessionHashTab[19]; +/** Spinlock protecting g_apSessionHashTab. */ +static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK; +/** Calculates bucket index into g_apSessionHashTab.*/ +#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab)) + +/** + * Kernel entry points + */ +int _init(void) +{ +#if 0 /* No IPRT logging before RTR0Init() is done! */ + LogFlowFunc(("vboxdrv:_init\n")); +#endif + + /* + * Prevent module autounloading. + */ + modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage); + if (pModCtl) + pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD; + else + cmn_err(CE_NOTE, "vboxdrv: failed to disable autounloading!\n"); + + /* + * Initialize IPRT R0 driver, which internally calls OS-specific r0 init. + */ + int rc = RTR0Init(0); + if (RT_SUCCESS(rc)) + { + /* + * Initialize the device extension + */ + rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION)); + if (RT_SUCCESS(rc)) + { + cmn_err(CE_CONT, "!tsc::mode %s @ tentative %lu Hz\n", SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz); + + /* + * Initialize the session hash table. + */ + memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); + rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDrvSol"); + if (RT_SUCCESS(rc)) + { + rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8); + if (!rc) + { + rc = mod_install(&g_VBoxDrvSolarisModLinkage); + if (!rc) + return rc; /* success */ + + ddi_soft_state_fini(&g_pVBoxDrvSolarisState); + LogRel(("vboxdrv: mod_install failed! rc=%d\n", rc)); + } + else + LogRel(("vboxdrv: failed to initialize soft state.\n")); + + RTSpinlockDestroy(g_Spinlock); + g_Spinlock = NIL_RTSPINLOCK; + } + else + { + LogRel(("VBoxDrvSolarisAttach: RTSpinlockCreate failed\n")); + rc = RTErrConvertToErrno(rc); + } + supdrvDeleteDevExt(&g_DevExt); + } + else + { + LogRel(("VBoxDrvSolarisAttach: supdrvInitDevExt failed\n")); + rc = EINVAL; + } + RTR0TermForced(); + } + else + { + LogRel(("VBoxDrvSolarisAttach: failed to init R0Drv\n")); + rc = RTErrConvertToErrno(rc); + } + memset(&g_DevExt, 0, sizeof(g_DevExt)); + + return rc; +} + + +int _fini(void) +{ + LogFlowFunc(("vboxdrv:_fini\n")); + + /* + * Undo the work we did at start (in the reverse order). + */ + int rc = mod_remove(&g_VBoxDrvSolarisModLinkage); + if (rc != 0) + return rc; + + supdrvDeleteDevExt(&g_DevExt); + + rc = RTSpinlockDestroy(g_Spinlock); + AssertRC(rc); + g_Spinlock = NIL_RTSPINLOCK; + + RTR0TermForced(); + + memset(&g_DevExt, 0, sizeof(g_DevExt)); + + ddi_soft_state_fini(&g_pVBoxDrvSolarisState); + return 0; +} + + +int _info(struct modinfo *pModInfo) +{ +#if 0 /* No IPRT logging before RTR0Init() is done! And yes this is called before _init()!*/ + LogFlowFunc(("vboxdrv:_init\n")); +#endif + int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo); + return e; +} + + +/** + * Attach entry point, to attach a device to the system or resume it. + * + * @param pDip The module structure instance. + * @param enmCmd Operation type (attach/resume). + * + * @return corresponding solaris error code. + */ +static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd) +{ + LogFlowFunc(("VBoxDrvSolarisAttach\n")); + + switch (enmCmd) + { + case DDI_ATTACH: + { + int rc; +#ifdef USE_SESSION_HASH + int instance = ddi_get_instance(pDip); + vbox_devstate_t *pState; + + if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS) + { + LogRel(("VBoxDrvSolarisAttach: state alloc failed\n")); + return DDI_FAILURE; + } + + pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance); +#endif + + /* + * Register for suspend/resume notifications + */ + rc = ddi_prop_create(DDI_DEV_T_NONE, pDip, DDI_PROP_CANSLEEP /* kmem alloc can sleep */, + "pm-hardware-state", "needs-suspend-resume", sizeof("needs-suspend-resume")); + if (rc != DDI_PROP_SUCCESS) + LogRel(("vboxdrv: Suspend/Resume notification registration failed.\n")); + + /* + * Register ourselves as a character device, pseudo-driver + */ +#ifdef VBOX_WITH_HARDENING + rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_SYS, S_IFCHR, 0 /*minor*/, DDI_PSEUDO, + 0, NULL, NULL, 0600); +#else + rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_SYS, S_IFCHR, 0 /*minor*/, DDI_PSEUDO, + 0, "none", "none", 0666); +#endif + if (rc == DDI_SUCCESS) + { + rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_USR, S_IFCHR, 1 /*minor*/, DDI_PSEUDO, + 0, "none", "none", 0666); + if (rc == DDI_SUCCESS) + { +#ifdef USE_SESSION_HASH + pState->pDip = pDip; +#endif + ddi_report_dev(pDip); + return DDI_SUCCESS; + } + ddi_remove_minor_node(pDip, NULL); + } + + return DDI_FAILURE; + } + + case DDI_RESUME: + { +#if 0 + RTSemFastMutexRequest(g_DevExt.mtxGip); + if (g_DevExt.pGipTimer) + RTTimerStart(g_DevExt.pGipTimer, 0); + + RTSemFastMutexRelease(g_DevExt.mtxGip); +#endif + RTPowerSignalEvent(RTPOWEREVENT_RESUME); + LogFlow(("vboxdrv: Awakened from suspend.\n")); + return DDI_SUCCESS; + } + + default: + return DDI_FAILURE; + } + + return DDI_FAILURE; +} + + +/** + * Detach entry point, to detach a device to the system or suspend it. + * + * @param pDip The module structure instance. + * @param enmCmd Operation type (detach/suspend). + * + * @return corresponding solaris error code. + */ +static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd) +{ + LogFlowFunc(("VBoxDrvSolarisDetach\n")); + switch (enmCmd) + { + case DDI_DETACH: + { +#ifndef USE_SESSION_HASH + ddi_remove_minor_node(pDip, NULL); +#else + int instance = ddi_get_instance(pDip); + vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance); + ddi_remove_minor_node(pDip, NULL); + ddi_soft_state_free(g_pVBoxDrvSolarisState, instance); +#endif + ddi_prop_remove_all(pDip); + return DDI_SUCCESS; + } + + case DDI_SUSPEND: + { +#if 0 + RTSemFastMutexRequest(g_DevExt.mtxGip); + if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0) + RTTimerStop(g_DevExt.pGipTimer); + + RTSemFastMutexRelease(g_DevExt.mtxGip); +#endif + RTPowerSignalEvent(RTPOWEREVENT_SUSPEND); + LogFlow(("vboxdrv: Falling to suspend mode.\n")); + return DDI_SUCCESS; + + } + + default: + return DDI_FAILURE; + } +} + + +/** + * Quiesce not-needed entry point, as Solaris 10 doesn't have any + * ddi_quiesce_not_needed() function. + * + * @param pDip The module structure instance. + * + * @return corresponding solaris error code. + */ +static int VBoxDrvSolarisQuiesceNotNeeded(dev_info_t *pDip) +{ + return DDI_SUCCESS; +} + + +/** + * open() worker. + */ +static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred) +{ + const bool fUnrestricted = getminor(*pDev) == 0; + PSUPDRVSESSION pSession; + int rc; + + LogFlowFunc(("VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev)); + + /* + * Validate input + */ + if ( (getminor(*pDev) != 0 && getminor(*pDev) != 1) + || fType != OTYP_CHR) + return EINVAL; /* See mmopen for precedent. */ + +#ifndef USE_SESSION_HASH + /* + * Locate a new device open instance. + * + * For each open call we'll allocate an item in the soft state of the device. + * The item index is stored in the dev_t. I hope this is ok... + */ + vbox_devstate_t *pState = NULL; + unsigned iOpenInstance; + for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++) + { + if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */ + && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS) + { + pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance); + break; + } + } + if (!pState) + { + LogRel(("VBoxDrvSolarisOpen: too many open instances.\n")); + return ENXIO; + } + + /* + * Create a new session. + */ + rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession); + if (RT_SUCCESS(rc)) + { + pSession->Uid = crgetruid(pCred); + pSession->Gid = crgetrgid(pCred); + + pState->pSession = pSession; + *pDev = makedevice(getmajor(*pDev), iOpenInstance); + LogFlow(("VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", + *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() )); + return 0; + } + + /* failed - clean up */ + ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance); + +#else + /* + * Create a new session. + * Sessions in Solaris driver are mostly useless. It's however needed + * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl() + */ + rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession); + if (RT_SUCCESS(rc)) + { + unsigned iHash; + + pSession->Uid = crgetruid(pCred); + pSession->Gid = crgetrgid(pCred); + + /* + * Insert it into the hash table. + */ +# error "Only one entry per process!" + iHash = SESSION_HASH(pSession->Process); + RTSpinlockAcquire(g_Spinlock); + pSession->pNextHash = g_apSessionHashTab[iHash]; + g_apSessionHashTab[iHash] = pSession; + RTSpinlockRelease(g_Spinlock); + LogFlow(("VBoxDrvSolarisOpen success\n")); + } + + int instance; + for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++) + { + vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance); + if (pState) + break; + } + + if (instance >= DEVICE_MAXINSTANCES) + { + LogRel(("VBoxDrvSolarisOpen: All instances exhausted\n")); + return ENXIO; + } + + *pDev = makedevice(getmajor(*pDev), instance); +#endif + + return VBoxSupDrvErr2SolarisErr(rc); +} + + +static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred) +{ + LogFlowFunc(("VBoxDrvSolarisClose: Dev=%#x\n", Dev)); + +#ifndef USE_SESSION_HASH + /* + * Get the session and free the soft state item. + */ + vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev)); + if (!pState) + { + LogRel(("VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev))); + return EFAULT; + } + + PSUPDRVSESSION pSession = pState->pSession; + pState->pSession = NULL; + ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev)); + + if (!pSession) + { + LogRel(("VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev))); + return EFAULT; + } + LogFlow(("VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", + Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() )); + +#else + const RTPROCESS Process = RTProcSelf(); + const unsigned iHash = SESSION_HASH(Process); + PSUPDRVSESSION pSession; + + /* + * Remove from the hash table. + */ + RTSpinlockAcquire(g_Spinlock); + pSession = g_apSessionHashTab[iHash]; + if (pSession) + { + if (pSession->Process == Process) + { + g_apSessionHashTab[iHash] = pSession->pNextHash; + pSession->pNextHash = NULL; + } + else + { + PSUPDRVSESSION pPrev = pSession; + pSession = pSession->pNextHash; + while (pSession) + { + if (pSession->Process == Process) + { + pPrev->pNextHash = pSession->pNextHash; + pSession->pNextHash = NULL; + break; + } + + /* next */ + pPrev = pSession; + pSession = pSession->pNextHash; + } + } + } + RTSpinlockRelease(g_Spinlock); + if (!pSession) + { + LogRel(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n", (int)Process)); + return EFAULT; + } +#endif + + /* + * Close the session. + */ + supdrvSessionRelease(pSession); + return 0; +} + + +static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred) +{ + LogFlowFunc(("VBoxDrvSolarisRead")); + return 0; +} + + +static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred) +{ + LogFlowFunc(("VBoxDrvSolarisWrite")); + return 0; +} + + +/** + * Driver ioctl, an alternate entry point for this character driver. + * + * @param Dev Device number + * @param iCmd Operation identifier + * @param pArgs Arguments from user to driver + * @param Mode Information bitfield (read/write, address space etc.) + * @param pCred User credentials + * @param pVal Return value for calling process. + * + * @return corresponding solaris error code. + */ +static int VBoxDrvSolarisIOCtl(dev_t Dev, int iCmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal) +{ +#ifndef USE_SESSION_HASH + /* + * Get the session from the soft state item. + */ + vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev)); + if (!pState) + { + LogRel(("VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev))); + return EINVAL; + } + + PSUPDRVSESSION pSession = pState->pSession; + if (!pSession) + { + LogRel(("VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev))); + return DDI_SUCCESS; + } +#else + const RTPROCESS Process = RTProcSelf(); + const unsigned iHash = SESSION_HASH(Process); + PSUPDRVSESSION pSession; + const bool fUnrestricted = getminor(Dev) == 0; + + /* + * Find the session. + */ + RTSpinlockAcquire(g_Spinlock); + pSession = g_apSessionHashTab[iHash]; + while (pSession && pSession->Process != Process && pSession->fUnrestricted == fUnrestricted); + pSession = pSession->pNextHash; + RTSpinlockRelease(g_Spinlock); + if (!pSession) + { + LogRel(("VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x Dev=%#x\n", + (int)Process, iCmd, (int)Dev)); + return EINVAL; + } +#endif + + /* + * Deal with the two high-speed IOCtl that takes it's arguments from + * the session and iCmd, and only returns a VBox status code. + */ + AssertCompile((SUP_IOCTL_FAST_DO_FIRST & 0xff) == (SUP_IOCTL_FLAG | 64)); + if ( (unsigned)(iCmd - SUP_IOCTL_FAST_DO_FIRST) < (unsigned)32 + && pSession->fUnrestricted) + { + *pVal = supdrvIOCtlFast(iCmd - SUP_IOCTL_FAST_DO_FIRST, pArgs, &g_DevExt, pSession); + return 0; + } + + return VBoxDrvSolarisIOCtlSlow(pSession, iCmd, Mode, pArgs); +} + + +/** @def IOCPARM_LEN + * Gets the length from the ioctl number. + * This is normally defined by sys/ioccom.h on BSD systems... + */ +#ifndef IOCPARM_LEN +# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK ) +#endif + + +/** + * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions. + * + * @returns Solaris errno. + * + * @param pSession The session. + * @param iCmd The IOCtl command. + * @param Mode Information bitfield (for specifying ownership of data) + * @param iArg User space address of the request buffer. + */ +static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg) +{ + int rc; + uint32_t cbBuf = 0; + union + { + SUPREQHDR Hdr; + uint8_t abBuf[64]; + } StackBuf; + PSUPREQHDR pHdr; + + + /* + * Read the header. + */ + if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr))) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr))); + return EINVAL; + } + rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode); + if (RT_UNLIKELY(rc)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc)); + return EFAULT; + } + if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd)); + return EINVAL; + } + cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut); + if (RT_UNLIKELY( StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr) + || StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr) + || cbBuf > _1M*16)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd)); + return EINVAL; + } + + /* + * Buffer the request. + */ + if (cbBuf <= sizeof(StackBuf)) + pHdr = &StackBuf.Hdr; + else + { + pHdr = RTMemTmpAlloc(cbBuf); + if (RT_UNLIKELY(!pHdr)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd)); + return ENOMEM; + } + } + rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode); + if (RT_UNLIKELY(rc)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc)); + if (pHdr != &StackBuf.Hdr) + RTMemFree(pHdr); + return EFAULT; + } + + /* + * Process the IOCtl. + */ + rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr, cbBuf); + + /* + * Copy ioctl data and output buffer back to user space. + */ + if (RT_LIKELY(!rc)) + { + uint32_t cbOut = pHdr->cbOut; + if (RT_UNLIKELY(cbOut > cbBuf)) + { + LogRel(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd)); + cbOut = cbBuf; + } + rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode); + if (RT_UNLIKELY(rc != 0)) + { + /* this is really bad */ + LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc)); + rc = EFAULT; + } + } + else + rc = EINVAL; + + if (pHdr != &StackBuf.Hdr) + RTMemTmpFree(pHdr); + return rc; +} + + +/** + * The SUPDRV IDC entry point. + * + * @returns VBox status code, see supdrvIDC. + * @param uReq The request code. + * @param pReq The request. + */ +int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq) +{ + PSUPDRVSESSION pSession; + + /* + * Some quick validations. + */ + if (RT_UNLIKELY(!RT_VALID_PTR(pReq))) + return VERR_INVALID_POINTER; + + pSession = pReq->pSession; + if (pSession) + { + if (RT_UNLIKELY(!RT_VALID_PTR(pSession))) + return VERR_INVALID_PARAMETER; + if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt)) + return VERR_INVALID_PARAMETER; + } + else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT)) + return VERR_INVALID_PARAMETER; + + /* + * Do the job. + */ + return supdrvIDC(uReq, &g_DevExt, pSession, pReq); +} + + +/** + * Converts an supdrv error code to a solaris error code. + * + * @returns corresponding solaris error code. + * @param rc IPRT status code. + */ +static int VBoxSupDrvErr2SolarisErr(int rc) +{ + switch (rc) + { + case VINF_SUCCESS: return 0; + case VERR_GENERAL_FAILURE: return EACCES; + case VERR_INVALID_PARAMETER: return EINVAL; + case VERR_INVALID_MAGIC: return EILSEQ; + case VERR_INVALID_HANDLE: return ENXIO; + case VERR_INVALID_POINTER: return EFAULT; + case VERR_LOCK_FAILED: return ENOLCK; + case VERR_ALREADY_LOADED: return EEXIST; + case VERR_PERMISSION_DENIED: return EPERM; + case VERR_VERSION_MISMATCH: return ENOSYS; + } + + return EPERM; +} + + +void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession) +{ + NOREF(pDevExt); + NOREF(pSession); +} + + +void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser) +{ + NOREF(pDevExt); NOREF(pSession); NOREF(pvUser); +} + + +void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser) +{ + NOREF(pDevExt); NOREF(pSession); NOREF(pvUser); +} + + +/** + * Initializes any OS specific object creator fields. + */ +void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession) +{ + NOREF(pObj); + NOREF(pSession); +} + + +/** + * Checks if the session can access the object. + * + * @returns true if a decision has been made. + * @returns false if the default access policy should be applied. + * + * @param pObj The object in question. + * @param pSession The session wanting to access the object. + * @param pszObjName The object name, can be NULL. + * @param prc Where to store the result when returning true. + */ +bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc) +{ + NOREF(pObj); + NOREF(pSession); + NOREF(pszObjName); + NOREF(prc); + return false; +} + + +bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt) +{ + return false; +} + + +bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void) +{ + /** @todo verify this. */ + return false; +} + + +bool VBOXCALL supdrvOSAreTscDeltasInSync(void) +{ + return false; +} + + +#if defined(VBOX_WITH_NATIVE_SOLARIS_LOADING) \ + && !defined(VBOX_WITHOUT_NATIVE_R0_LOADER) + +int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename) +{ + pImage->idSolMod = -1; + pImage->pSolModCtl = NULL; + +# if 1 /* This approach requires _init/_fini/_info stubs. */ + /* + * Construct a filename that escapes the module search path and let us + * specify a root path. + */ + /** @todo change this to use modctl and use_path=0. */ + const char *pszName = RTPathFilename(pszFilename); + AssertReturn(pszName, VERR_INVALID_PARAMETER); + char *pszSubDir = RTStrAPrintf2("../../../../../../../../../../..%.*s", pszName - pszFilename - 1, pszFilename); + if (!pszSubDir) + return VERR_NO_STR_MEMORY; + int idMod = modload(pszSubDir, pszName); + if (idMod == -1) + { + /* This is an horrible hack for avoiding the mod-present check in + modrload on S10. Fortunately, nobody else seems to be using that + variable... */ + extern int swaploaded; + int saved_swaploaded = swaploaded; + swaploaded = 0; + idMod = modload(pszSubDir, pszName); + swaploaded = saved_swaploaded; + } + RTStrFree(pszSubDir); + if (idMod == -1) + { + LogRel(("modload(,%s): failed, could be anything...\n", pszFilename)); + return VERR_LDR_GENERAL_FAILURE; + } + + modctl_t *pModCtl = mod_hold_by_id(idMod); + if (!pModCtl) + { + LogRel(("mod_hold_by_id(,%s): failed, weird.\n", pszFilename)); + /* No point in calling modunload. */ + return VERR_LDR_GENERAL_FAILURE; + } + pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD | MOD_NOUNLOAD; /* paranoia */ + +# else + + const int idMod = -1; + modctl_t *pModCtl = mod_hold_by_name(pszFilename); + if (!pModCtl) + { + LogRel(("mod_hold_by_name failed for '%s'\n", pszFilename)); + return VERR_LDR_GENERAL_FAILURE; + } + + int rc = kobj_load_module(pModCtl, 0 /*use_path*/); + if (rc != 0) + { + LogRel(("kobj_load_module failed with rc=%d for '%s'\n", rc, pszFilename)); + mod_release_mod(pModCtl); + return RTErrConvertFromErrno(rc); + } +# endif + + /* + * Get the module info. + * + * Note! The text section is actually not at mi_base, but and the next + * alignment boundrary and there seems to be no easy way of + * getting at this address. This sabotages supdrvOSLdrLoad. + * Bastards! + */ + struct modinfo ModInfo; + kobj_getmodinfo(pModCtl->mod_mp, &ModInfo); + pImage->pvImage = ModInfo.mi_base; + pImage->idSolMod = idMod; + pImage->pSolModCtl = pModCtl; + + mod_release_mod(pImage->pSolModCtl); + LogRel(("supdrvOSLdrOpen: succeeded for '%s' (mi_base=%p mi_size=%#x), id=%d ctl=%p\n", + pszFilename, ModInfo.mi_base, ModInfo.mi_size, idMod, pModCtl)); + return VINF_SUCCESS; +} + + +int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, + const uint8_t *pbImageBits, const char *pszSymbol) +{ + NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol); + if (kobj_addrcheck(pImage->pSolModCtl->mod_mp, pv)) + return VERR_INVALID_PARAMETER; + return VINF_SUCCESS; +} + + +/** + * Resolves a module entry point address. + * + * @returns VBox status code. + * @param pImage The image. + * @param pszSymbol The symbol name. + * @param ppvValue Where to store the value. On input this holds + * the symbol value SUPLib calculated. + */ +static int supdrvSolLdrResolvEp(PSUPDRVLDRIMAGE pImage, const char *pszSymbol, void **ppvValue) +{ + /* Don't try resolve symbols which, according to SUPLib, aren't there. */ + if (!*ppvValue) + return VINF_SUCCESS; + + uintptr_t uValue = modlookup_by_modctl(pImage->pSolModCtl, pszSymbol); + if (!uValue) + { + LogRel(("supdrvOSLdrLoad on %s failed to resolve %s\n", pImage->szName, pszSymbol)); + return VERR_SYMBOL_NOT_FOUND; + } + *ppvValue = (void *)uValue; + return VINF_SUCCESS; +} + + +int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq) +{ +#if 0 /* This doesn't work because of text alignment. */ + /* + * Comparing is very very difficult since text and data may be allocated + * separately. + */ + size_t cbCompare = RT_MIN(pImage->cbImageBits, 64); + if (memcmp(pImage->pvImage, pbImageBits, cbCompare)) + { + LogRel(("Image mismatch: %s (%p)\n", pImage->szName, pImage->pvImage)); + LogRel(("Native: %.*Rhxs\n", cbCompare, pImage->pvImage)); + LogRel(("SUPLib: %.*Rhxs\n", cbCompare, pbImageBits)); + return VERR_LDR_MISMATCH_NATIVE; + } +#endif + + /* + * Get the exported symbol addresses. + */ + int rc; + modctl_t *pModCtl = mod_hold_by_id(pImage->idSolMod); + if (pModCtl && pModCtl == pImage->pSolModCtl) + { + uint32_t iSym = pImage->cSymbols; + while (iSym-- > 0) + { + const char *pszSymbol = &pImage->pachStrTab[pImage->paSymbols[iSym].offName]; + uintptr_t uValue = modlookup_by_modctl(pImage->pSolModCtl, pszSymbol); + if (!uValue) + { + LogRel(("supdrvOSLdrLoad on %s failed to resolve the exported symbol: '%s'\n", pImage->szName, pszSymbol)); + break; + } + uintptr_t offSymbol = uValue - (uintptr_t)pImage->pvImage; + pImage->paSymbols[iSym].offSymbol = offSymbol; + if (pImage->paSymbols[iSym].offSymbol != (int32_t)offSymbol) + { + LogRel(("supdrvOSLdrLoad on %s symbol out of range: %p (%s) \n", pImage->szName, offSymbol, pszSymbol)); + break; + } + } + + rc = iSym == UINT32_MAX ? VINF_SUCCESS : VERR_LDR_GENERAL_FAILURE; + + /* + * Get the standard module entry points. + */ + if (RT_SUCCESS(rc)) + { + rc = supdrvSolLdrResolvEp(pImage, "ModuleInit", (void **)&pImage->pfnModuleInit); + if (RT_SUCCESS(rc)) + rc = supdrvSolLdrResolvEp(pImage, "ModuleTerm", (void **)&pImage->pfnModuleTerm); + + switch (pReq->u.In.eEPType) + { + case SUPLDRLOADEP_VMMR0: + { + if (RT_SUCCESS(rc)) + rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryFast", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryFast); + if (RT_SUCCESS(rc)) + rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryEx", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryEx); + break; + } + + case SUPLDRLOADEP_SERVICE: + { + /** @todo we need the name of the entry point. */ + return VERR_NOT_SUPPORTED; + } + } + } + + mod_release_mod(pImage->pSolModCtl); + } + else + { + LogRel(("mod_hold_by_id failed in supdrvOSLdrLoad on %s: %p\n", pImage->szName, pModCtl)); + rc = VERR_LDR_MISMATCH_NATIVE; + } + return rc; +} + + +void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage) +{ +# if 1 + pImage->pSolModCtl->mod_loadflags &= ~MOD_NOUNLOAD; + int rc = modunload(pImage->idSolMod); + if (rc) + LogRel(("modunload(%u (%s)) failed: %d\n", pImage->idSolMod, pImage->szName, rc)); +# else + kobj_unload_module(pImage->pSolModCtl); +# endif + pImage->pSolModCtl = NULL; + pImage->idSolMod = NULL; +} + +#else /* !VBOX_WITH_NATIVE_SOLARIS_LOADING */ + +int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename) +{ + NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename); + return VERR_NOT_SUPPORTED; +} + + +int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, + const uint8_t *pbImageBits, const char *pszSymbol) +{ + NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol); + return VERR_NOT_SUPPORTED; +} + + +int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq) +{ + NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq); + return VERR_NOT_SUPPORTED; +} + + +void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage) +{ + NOREF(pDevExt); NOREF(pImage); +} + +#endif /* !VBOX_WITH_NATIVE_SOLARIS_LOADING */ + + +void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename) +{ + NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename); +} + + +void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage) +{ + NOREF(pDevExt); NOREF(pImage); +} + + +int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, + const char *pszSymbol, size_t cchSymbol, void **ppvSymbol) +{ + RT_NOREF(pDevExt, pImage, pszSymbol, cchSymbol, ppvSymbol); + return VERR_WRONG_ORDER; +} + + +void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage) +{ + RT_NOREF(pDevExt, pImage); + AssertFailed(); +} + + +void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage) +{ + RT_NOREF(pDevExt, pImage); + AssertFailed(); +} + +#ifdef SUPDRV_WITH_MSR_PROBER + +int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue) +{ +/** @todo cmi_hdl_rdmsr can safely do this. there is also the on_trap() fun + * for catching traps that could possibly be used directly. */ + NOREF(uMsr); NOREF(idCpu); NOREF(puValue); + return VERR_NOT_SUPPORTED; +} + + +int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue) +{ +/** @todo cmi_hdl_wrmsr can safely do this. */ + NOREF(uMsr); NOREF(idCpu); NOREF(uValue); + return VERR_NOT_SUPPORTED; +} + + +int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq) +{ + NOREF(idCpu); NOREF(pReq); + return VERR_NOT_SUPPORTED; +} + +#endif /* SUPDRV_WITH_MSR_PROBER */ + + +SUPR0DECL(int) SUPR0HCPhysToVirt(RTHCPHYS HCPhys, void **ppv) +{ + AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INVALID_POINTER); + AssertReturn(HCPhys != NIL_RTHCPHYS, VERR_INVALID_POINTER); + HCPhys >>= PAGE_SHIFT; + AssertReturn(HCPhys <= physmax, VERR_INVALID_POINTER); + *ppv = hat_kpm_pfn2va(HCPhys); + return VINF_SUCCESS; +} + + +RTDECL(int) SUPR0PrintfV(const char *pszFormat, va_list va) +{ + /* cmn_err() acquires adaptive mutexes. Not preemption safe, see @bugref{6657}. */ + if (RTThreadPreemptIsEnabled(NIL_RTTHREAD)) + { + char szMsg[512]; + RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va); + szMsg[sizeof(szMsg) - 1] = '\0'; + + cmn_err(CE_CONT, "%s", szMsg); + } + return 0; +} + + +SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void) +{ + return 0; +} + + +SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook) +{ + RT_NOREF(fCtxHook); + return false; +} + + +SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook) +{ + RT_NOREF(fCtxHook); +} + diff --git a/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp new file mode 100644 index 00000000..8e12b929 --- /dev/null +++ b/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp @@ -0,0 +1,245 @@ +/* $Id: SUPLib-solaris.cpp $ */ +/** @file + * VirtualBox Support Library - Solaris specific parts. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_SUP +#ifdef IN_SUP_HARDENED_R3 +# undef DEBUG /* Warning: disables RT_STRICT */ +# ifndef LOG_DISABLED +# define LOG_DISABLED +# endif +# define RTLOG_REL_DISABLED +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../SUPLibInternal.h" +#include "../SUPDrvIOC.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** Solaris device link - system. */ +#define DEVICE_NAME_SYS "/devices/pseudo/vboxdrv@0:vboxdrv" +/** Solaris device link - user. */ +#define DEVICE_NAME_USR "/devices/pseudo/vboxdrv@0:vboxdrvu" +/** Solaris device link - system (non-global zone). */ +#define DEVICE_NAME_SYS_ZONE "/dev/vboxdrv" +/** Solaris device link - user (non-global zone). */ +#define DEVICE_NAME_USR_ZONE "/dev/vboxdrvu" + + + +DECLHIDDEN(int) suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, uint32_t fFlags, SUPINITOP *penmWhat, PRTERRINFO pErrInfo) +{ + /* + * Nothing to do if pre-inited. + */ + if (fPreInited) + return VINF_SUCCESS; + + /* + * Open dummy files to preallocate file descriptors, see @bugref{4650}. + */ + for (int i = 0; i < SUPLIB_FLT_DUMMYFILES; i++) + { + pThis->ahDummy[i] = -1; + int hDummy = open("/dev/null", O_RDWR, 0); + if (hDummy >= 0) + { + if (fcntl(hDummy, F_SETFD, FD_CLOEXEC) == 0) + pThis->ahDummy[i] = hDummy; + else + { + close(hDummy); + LogRel(("Failed to set close on exec [%d] /dev/null! errno=%d\n", i, errno)); + } + } + else + LogRel(("Failed to open[%d] /dev/null! errno=%d\n", i, errno)); + } + + /* + * Try to open the device. + */ + const char *pszDeviceNm; + if (getzoneid() == GLOBAL_ZONEID) + pszDeviceNm = fFlags & SUPR3INIT_F_UNRESTRICTED ? DEVICE_NAME_SYS : DEVICE_NAME_USR; + else + pszDeviceNm = fFlags & SUPR3INIT_F_UNRESTRICTED ? DEVICE_NAME_SYS_ZONE : DEVICE_NAME_USR_ZONE; + int hDevice = open(pszDeviceNm, O_RDWR, 0); + if (hDevice < 0) + { + int rc; + switch (errno) + { + case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break; + case EPERM: + case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break; + case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break; + default: rc = VERR_VM_DRIVER_OPEN_ERROR; break; + } + LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", pszDeviceNm, errno, rc)); + return rc; + } + + /* + * Mark the file handle close on exec. + */ + if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) != 0) + { +#ifdef IN_SUP_HARDENED_R3 + int rc = VERR_INTERNAL_ERROR; +#else + int err = errno; + int rc = RTErrConvertFromErrno(err); + LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d (%Rrc)\n", err, rc)); +#endif + close(hDevice); + return rc; + } + + pThis->hDevice = hDevice; + pThis->fUnrestricted = RT_BOOL(fFlags & SUPR3INIT_F_UNRESTRICTED); + return VINF_SUCCESS; +} + + +DECLHIDDEN(int) suplibOsTerm(PSUPLIBDATA pThis) +{ + /* + * Close the dummy files first. + */ + for (int i = 0; i < SUPLIB_FLT_DUMMYFILES; i++) + { + if (pThis->ahDummy[i] != -1) + { + close(pThis->ahDummy[i]); + pThis->ahDummy[i] = -1; + } + } + + /* + * Check if we're initialized + */ + if (pThis->hDevice != (intptr_t)NIL_RTFILE) + { + if (close(pThis->hDevice)) + AssertFailed(); + pThis->hDevice = (intptr_t)NIL_RTFILE; + } + + return VINF_SUCCESS; +} + + +#ifndef IN_SUP_HARDENED_R3 + +DECLHIDDEN(int) suplibOsInstall(void) +{ + return VERR_NOT_IMPLEMENTED; +} + +DECLHIDDEN(int) suplibOsUninstall(void) +{ + return VERR_NOT_IMPLEMENTED; +} + + +DECLHIDDEN(int) suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq) +{ + if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0)) + return VINF_SUCCESS; + return RTErrConvertFromErrno(errno); +} + + +DECLHIDDEN(int) suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu) +{ + int rc = ioctl(pThis->hDevice, uFunction, idCpu); + if (rc == -1) + rc = errno; + return rc; +} + + +DECLHIDDEN(int) suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, uint32_t fFlags, void **ppvPages) +{ + RT_NOREF(pThis, fFlags); + *ppvPages = mmap(NULL, cPages * PAGE_SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (*ppvPages != (void *)-1) + return VINF_SUCCESS; + if (errno == EAGAIN) + return VERR_NO_MEMORY; + return RTErrConvertFromErrno(errno); +} + + +DECLHIDDEN(int) suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages) +{ + NOREF(pThis); + munmap(pvPages, cPages * PAGE_SIZE); + return VINF_SUCCESS; +} + +#endif /* !IN_SUP_HARDENED_R3 */ + diff --git a/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c b/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c new file mode 100644 index 00000000..ba0b5e3e --- /dev/null +++ b/src/VBox/HostDrivers/Support/solaris/SUPR0IdcClient-solaris.c @@ -0,0 +1,66 @@ +/* $Id: SUPR0IdcClient-solaris.c $ */ +/** @file + * VirtualBox Support Driver - IDC Client Lib, Solaris Specific Code. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "../SUPR0IdcClientInternal.h" +#include + + +int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq) +{ + return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr); +} + + +int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq) +{ + return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq); +} + + +int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq) +{ + int rc = SUPDrvSolarisIDC(iReq, pReq); + if (RT_SUCCESS(rc)) + rc = pReq->rc; + + NOREF(pHandle); + return rc; +} + diff --git a/src/VBox/HostDrivers/Support/solaris/load.sh b/src/VBox/HostDrivers/Support/solaris/load.sh new file mode 100755 index 00000000..b2f86bab --- /dev/null +++ b/src/VBox/HostDrivers/Support/solaris/load.sh @@ -0,0 +1,128 @@ +#!/bin/bash +# $Id: load.sh $ +## @file +# For development. +# + +# +# Copyright (C) 2006-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox 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. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +DRVNAME="vboxdrv" +DRIVERS_USING_IT="vboxusb vboxusbmon vboxnet vboxflt vboxbow" + +DRVFILE=`dirname "$0"` +DRVFILE=`cd "$DRVFILE" && pwd` +DRVFILE="$DRVFILE/$DRVNAME" +if [ ! -f "$DRVFILE" ]; then + echo "load.sh: Cannot find $DRVFILE or it's not a file..." + exit 1; +fi +if [ ! -f "$DRVFILE.conf" ]; then + echo "load.sh: Cannot find $DRVFILE.conf or it's not a file..." + exit 1; +fi + +SUDO=sudo +hash "${SUDO}" 2> /dev/null || SUDO=pfexec +#set -x + +# Disable the zone access service. +servicefound=`svcs -H "virtualbox/zoneaccess" 2>/dev/null | grep '^online'` +if test ! -z "$servicefound"; then + $SUDO svcadm disable svc:/application/virtualbox/zoneaccess:default +fi + +# Unload driver that may depend on the driver we're going to (re-)load +# as well as the driver itself. +for drv in $DRIVERS_USING_IT $DRVNAME; +do + LOADED=`modinfo | grep -w "$drv"` + if test -n "$LOADED"; then + MODID=`echo "$LOADED" | cut -d ' ' -f 1` + $SUDO modunload -i $MODID; + LOADED=`modinfo | grep -w "$drv"`; + if test -n "$LOADED"; then + echo "load.sh: failed to unload $drv"; + dmesg | tail + exit 1; + fi + fi +done + +# +# Reconfigure the driver so it get a major number. +# +# Note! We have to copy the driver and config files to somewhere the kernel can +# find them. It is searched for as drv/${DRVNAME}.conf in +# kobj_module_path, which is usually: +# /platform/i86pc/kernel /kernel /usr/kernel +# To try prevent bad drivers from being loaded on the next boot, we remove +# always the files. +# +MY_RC=1 +set -e +$SUDO rm -f \ + "/platform/i86pc/kernel/drv/${DRVNAME}.conf" \ + "/platform/i86pc/kernel/drv/${DRVNAME}" \ + "/platform/i86pc/kernel/drv/amd64/${DRVNAME}" +sync +$SUDO cp "${DRVFILE}" /platform/i86pc/kernel/drv/amd64/ +$SUDO cp "${DRVFILE}.conf" /platform/i86pc/kernel/drv/ +set +e + +$SUDO rem_drv $DRVNAME +if $SUDO add_drv -v $DRVNAME; then + sync + if $SUDO modload "/platform/i86pc/kernel/drv/amd64/${DRVNAME}"; then + echo "load.sh: successfully loaded the driver" + modinfo | grep -w "$DRVNAME" + MY_RC=0 + if test ! -h "/dev/vboxdrv"; then + $SUDO ln -sf "/devices/pseudo/vboxdrv@0:vboxdrv" /dev/vboxdrv + $SUDO chmod 0666 /dev/vboxdrv + fi + else + dmesg | tail + echo "load.sh: modload failed" + fi +else + dmesg | tail + echo "load.sh: add_drv failed." +fi + +$SUDO rm -f \ + "/platform/i86pc/kernel/drv/${DRVNAME}.conf" \ + "/platform/i86pc/kernel/drv/${DRVNAME}" \ + "/platform/i86pc/kernel/drv/amd64/${DRVNAME}" +sync + +exit $MY_RC; + diff --git a/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf b/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf new file mode 100644 index 00000000..fcc02230 --- /dev/null +++ b/src/VBox/HostDrivers/Support/solaris/vboxdrv.conf @@ -0,0 +1,43 @@ +# $Id: vboxdrv.conf $ +## @file +# VirtualBox Solaris Host Driver Configuration. +# + +# +# Copyright (C) 2007-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox 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. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# This needs to go into /platform/i86pc/kernel/drv, +# while the 64-bit driver object goes into the amd64 +# subdirectory (32-bit drivers goes into the same +# directory). After copying execute add_drv vboxdrv. +# +name="vboxdrv" parent="pseudo" instance=0; + -- cgit v1.2.3