Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

VBoxBFE.cpp

Go to the documentation of this file.
/** @file
 *
 * VBox frontends: Basic Frontend (BFE):
 * VBoxBFE main routines
 *
 * VBoxBFE is a limited frontend that sits directly on the Virtual Machine
 * Manager (VMM) and does _not_ use COM to communicate.
 * On Linux and Windows, VBoxBFE is based on SDL; on L4 it's based on the
 * L4 console. Much of the code has been copied over from the other frontends
 * in VBox/Main/ and src/Frontends/VBoxSDL/.
 */

/*
 * Copyright (C) 2006-2007 innotek GmbH
 *
 * 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 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.
 */

/*******************************************************************************
*   Header Files                                                               *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_GUI

#ifndef VBOXBFE_WITHOUT_COM
# include <VBox/com/Guid.h>
# include <VBox/com/string.h>
using namespace com;
#endif

#include <VBox/types.h>
#include <VBox/err.h>
#include <VBox/param.h>
#include <VBox/pdm.h>
#include <VBox/version.h>
#ifdef VBOXBFE_WITH_USB
# include <VBox/vusb.h>
#endif
#include <VBox/log.h>
#include <iprt/path.h>
#include <iprt/string.h>
#include <iprt/runtime.h>
#include <iprt/assert.h>
#include <iprt/semaphore.h>
#include <iprt/stream.h>
#include <iprt/thread.h>
#include <iprt/uuid.h>
#include <iprt/file.h>
#include <iprt/alloca.h>
#include <iprt/ctype.h>

#include "VBoxBFE.h"

#include <stdio.h>
#include <stdlib.h> /* putenv */
#include <errno.h>

#if defined(RT_OS_LINUX) || defined(RT_OS_L4)
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_tun.h>
#endif

#ifndef RT_OS_L4
#include <vector>
#endif

#include "ConsoleImpl.h"
#include "DisplayImpl.h"
#include "MouseImpl.h"
#include "KeyboardImpl.h"
#include "VMMDevInterface.h"
#include "StatusImpl.h"
#include "Framebuffer.h"
#include "MachineDebuggerImpl.h"
#ifdef VBOXBFE_WITH_USB
# include "HostUSBImpl.h"
#endif

#if defined(USE_SDL) && ! defined(RT_OS_L4)
#include "SDLConsole.h"
#include "SDLFramebuffer.h"
#endif

#ifdef RT_OS_L4
#include "L4Console.h"
#include "L4Framebuffer.h"
#endif

#ifdef RT_OS_L4
# ifndef L4API_l4v2onv4
#  include <l4/sys/ktrace.h>
# endif
# include <l4/vboxserver/file.h>
#endif

/*******************************************************************************
*   Defined Constants And Macros                                               *
*******************************************************************************/

#define VBOXSDL_ADVANCED_OPTIONS
#define MAC_STRING_LEN 12


/*******************************************************************************
*   Internal Functions                                                         *
*******************************************************************************/
static DECLCALLBACK(int) vboxbfeConfigConstructor(PVM pVM, void *pvUser);
static DECLCALLBACK(void) vmstateChangeCallback(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser);
static DECLCALLBACK(void) setVMErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL,
                                             const char *pszFormat, va_list args);
static DECLCALLBACK(int) VMPowerUpThread(RTTHREAD Thread, void *pvUser);


/*******************************************************************************
*   Global Variables                                                           *
*******************************************************************************/

PVM              pVM              = NULL;
Mouse           *gMouse           = NULL;
VMDisplay       *gDisplay         = NULL;
Keyboard        *gKeyboard        = NULL;
VMMDev          *gVMMDev          = NULL;
Framebuffer     *gFramebuffer     = NULL;
MachineDebugger *gMachineDebugger = NULL;
VMStatus        *gStatus          = NULL;
Console         *gConsole         = NULL;
#ifdef VBOXBFE_WITH_USB
HostUSB         *gHostUSB         = NULL;
#endif

VMSTATE machineState = VMSTATE_CREATING;

PPDMLED     mapFDLeds[2]      = {0};
PPDMLED     mapIDELeds[4]     = {0};

/** flag whether keyboard/mouse events are grabbed */
#ifdef RT_OS_L4
/** see <l4/input/macros.h> for key definitions */
int gHostKey; /* not used */
int gHostKeySym = KEY_RIGHTCTRL;
#elif defined (DEBUG_dmik)
// my mini kbd doesn't have RCTRL...
int gHostKey    = KMOD_RSHIFT;
int gHostKeySym = SDLK_RSHIFT;
#else
00153 int gHostKey    = KMOD_RCTRL;
int gHostKeySym = SDLK_RCTRL;
#endif
bool gfAllowFullscreenToggle = true;

static bool g_fIOAPIC = false;
static bool g_fACPI   = true;
static bool g_fAudio  = false;
#ifdef VBOXBFE_WITH_USB
static bool g_fUSB    = false;
#endif
static char *g_pszHdaFile   = NULL;
static char *g_pszHdbFile   = NULL;
static char *g_pszCdromFile = NULL;
static char *g_pszFdaFile   = NULL;
static const char *pszBootDevice = "IDE";
static uint32_t g_u32MemorySizeMB = 128;
static uint32_t g_u32VRamSizeMB = 4;
#ifdef VBOXSDL_ADVANCED_OPTIONS
static bool g_fRawR0 = true;
static bool g_fRawR3 = true;
static bool g_fPATM  = true;
static bool g_fCSAM  = true;
#endif
static bool g_fPreAllocRam = false;
static int  g_iBootMenu = 2;
00179 static bool g_fReleaseLog = true; /**< Set if we should open the release. */


/**
 * Network device config info.
 */
00185 typedef struct BFENetworkDevice
{
    enum
    {
        NOT_CONFIGURED = 0,
        NONE,
        NAT,
        HIF,
        INTNET
    }           enmType;    /**< The type of network driver. */
00195     bool        fSniff;     /**< Set if the network sniffer should be installed. */
00196     const char *pszSniff;   /**< Output file for the network sniffer. */
00197     PDMMAC      Mac;        /**< The mac address for the device. */
00198     const char *pszName;     /**< The device name of a HIF device. The name of the internal network. */
#if 1//defined(RT_OS_LINUX)
00200     bool        fHaveFd;    /**< Set if fd is valid. */
00201     int32_t     fd;         /**< The file descriptor of a HIF device.*/
#endif
} BFENETDEV, *PBFENETDEV;

/** Array of network device configurations. */
00206 static BFENETDEV g_aNetDevs[NetworkAdapterCount];


/** @todo currently this is only set but never read. */
00210 static char szError[512];


/**
 * Converts the passed in network option
 *
 * @returns Index into g_aNetDevs on success. (positive)
 * @returns VERR_INVALID_PARAMETER on failure. (negative)
 * @param   pszArg          The argument.
 * @param   cchRoot         The length of the argument root.
 */
00221 static int networkArg2Index(const char *pszArg, int cchRoot)
{
    uint32_t n;
    int rc = RTStrToUInt32Ex(&pszArg[cchRoot], NULL, 10, &n);
    if (VBOX_FAILURE(rc))
    {
        RTPrintf("Error: invalid network device option (rc=%Vrc): %s\n", rc, pszArg);
        return -1;
    }
    if (n < 1 || n > NetworkAdapterCount)
    {
        RTPrintf("Error: The network device number is out of range: %RU32 (1 <= 0 <= %u) (%s)\n",
                 n, NetworkAdapterCount, pszArg);
        return -1;
    }
    return n;
}

/**
 *  Generates a new unique MAC address based on our vendor ID and
 *  parts of a GUID.
 *
 * @returns iprt status code
 * @param pAddress An array into which to store the newly generated address
 */
00246 int GenerateMACAddress(char pAddress[MAC_STRING_LEN + 1])
{
    /*
     * Our strategy is as follows: the first three bytes are our fixed
     * vendor ID (080027). The remaining 3 bytes will be taken from the
     * start of a GUID. This is a fairly safe algorithm.
     */
    LogFlowFunc(("called\n"));
    RTUUID uuid;
    int rc = RTUuidCreate(&uuid);
    if (RT_FAILURE(rc))
    {
        LogFlowFunc(("RTUuidCreate failed, returning %Vrc\n", rc));
        return rc;
    }
    RTStrPrintf (pAddress, MAC_STRING_LEN + 1, "080027%02X%02X%02X",
                 uuid.au8[0], uuid.au8[1], uuid.au8[2]);
    LogFlowFunc(("generated MAC: '%s'\n", pAddress));
    return VINF_SUCCESS;
}                         

/**
 * Print a syntax error.
 *
 * @returns return value for main().
 * @param   pszMsg  The message format string.
 * @param   ...     Format arguments.
 */
00274 static int SyntaxError(const char *pszMsg, ...)
{
    va_list va;
    RTPrintf("error: ");
    va_start(va, pszMsg);
    RTPrintfV(pszMsg, va);
    va_end(va);
    return 1;
}


/**
 * Print a fatal error.
 *
 * @returns return value for main().
 * @param   pszMsg  The message format string.
 * @param   ...     Format arguments.
 */
00292 static int FatalError(const char *pszMsg, ...)
{
    va_list va;
    RTPrintf("fatal error: ");
    va_start(va, pszMsg);
    RTPrintfV(pszMsg, va);
    va_end(va);
    return 1;
}


/**
 * Print program usage.
 */
00306 static void show_usage()
{
    RTPrintf("Usage:\n"
             "  -hda <file>        Set first hard disk to file\n"
             "  -hdb <file>        Set second hard disk to file\n"
             "  -fda <file>        Set first floppy disk to file\n"
             "  -cdrom <file>      Set CDROM to file/device ('none' to unmount)\n"
             "  -boot <a|c|d>      Set boot device (a = floppy, c = first hard disk, d = DVD)\n"
             "  -boot menu <0|1|2> Boot menu (0 = disable, 1 = menu only, 2 = message + menu)\n"
             "  -m <size>          Set memory size in megabytes (default 128MB)\n"
             "  -vram <size>       Set size of video memory in megabytes\n"
             "  -prealloc          Force RAM pre-allocation\n"
             "  -fullscreen        Start VM in fullscreen mode\n"
             "  -nofstoggle        Forbid switching to/from fullscreen mode\n"
             "  -nohostkey         Disable hostkey\n"
             "  -[no]acpi          Enable or disable ACPI (default: enabled)\n"
             "  -[no]ioapic        Enable or disable the IO-APIC (default: disabled)\n"
             "  -audio             Enable audio\n"
#ifndef RT_OS_L4
             "  -natdev<1-N> [mac] Use NAT networking on network adapter <N>.  Use hardware\n"
             "                     address <mac> if specified.\n"
#endif
             "  -hifdev<1-N>       Use Host Interface Networking with host interface <int>\n"
             "      <int> [mac]    on network adapter <N>.  Use hardware address <mac> if\n"
             "                     specified.\n"
#ifndef RT_OS_L4
             "  -intnet<1-N>       Attach network adapter <N> to internal network <net>.  Use\n"
             "      <net> [mac]    hardware address <mac> if specified.\n"
#endif
#if 0
             "  -netsniff<1-N>     Enable packet sniffer\n"
#endif
#ifdef RT_OS_LINUX
             "  -tapfd<1-N> <fd>   Use existing TAP device, don't allocate\n"
#endif
#ifdef VBOX_VRDP
             "  -vrdp [port]       Listen for VRDP connections on port (default if not specified)\n"
#endif
#ifdef VBOX_SECURELABEL
             "  -securelabel       Display a secure VM label at the top of the screen\n"
             "  -seclabelfnt       TrueType (.ttf) font file for secure session label\n"
             "  -seclabelsiz       Font point size for secure session label (default 12)\n"
#endif
             "  -[no]rellog        Enable or disable the release log './VBoxBFE.log' (default: enabled)\n"
#ifdef VBOXSDL_ADVANCED_OPTIONS
             "  -[no]rawr0         Enable or disable raw ring 3\n"
             "  -[no]rawr3         Enable or disable raw ring 0\n"
             "  -[no]patm          Enable or disable PATM\n"
             "  -[no]csam          Enable or disable CSAM\n"
#endif
#ifdef RT_OS_L4
             "  -env <var=value>   Set the given environment variable to \"value\"\n"
#endif
             "\n");
}


/** entry point */
00364 int main(int argc, char **argv)
{
#ifdef RT_OS_L4
#ifndef L4API_l4v2onv4
    /* clear Fiasco kernel trace buffer */
    fiasco_tbuf_clear();
#endif
    /* set the environment.  Must be done before the runtime is
       initialised.  Yes, it really must. */
    for (int i = 0; i < argc; i++)
        if (strcmp(argv[i], "-env") == 0)
        {
            if (++i >= argc)
                return SyntaxError("missing argument to -env (format: var=value)!\n");
            /* add it to the environment */
            if (putenv(argv[i]) != 0)
                return SyntaxError("Error setting environment string %s.\n", argv[i]);
        }
#endif /* RT_OS_L4 */

    /*
     * Before we do *anything*, we initialize the runtime.
     */
    int rc = RTR3Init();
    if (VBOX_FAILURE(rc))
        return FatalError("RTR3Init failed rc=%Vrc\n", rc);


    bool fFullscreen = false;
#ifdef VBOX_VRDP
    int32_t portVRDP = -1;
#endif
#ifdef VBOX_SECURELABEL
    bool fSecureLabel = false;
    uint32_t secureLabelPointSize = 12;
    char *secureLabelFontFile = NULL;
#endif
    RTPrintf("VirtualBox Simple SDL GUI built %s %s\n", __DATE__, __TIME__);

    // less than one parameter is not possible
    if (argc < 2)
    {
        show_usage();
        return 1;
    }

    /*
     * Parse the command line arguments.
     */
    for (int curArg = 1; curArg < argc; curArg++)
    {
        const char * const pszArg = argv[curArg];
        if (strcmp(pszArg, "-boot") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing argument for boot drive!\n");
            if (strlen(argv[curArg]) != 1)
                return SyntaxError("invalid argument for boot drive! (%s)\n", argv[curArg]);
            rc = VINF_SUCCESS;
            switch (argv[curArg][0])
            {
                case 'a':
                {
                    pszBootDevice = "FLOPPY";
                    break;
                }

                case 'c':
                {
                    pszBootDevice = "IDE";
                    break;
                }

                case 'd':
                {
                    pszBootDevice = "DVD";
                    break;
                }

                default:
                    return SyntaxError("wrong argument for boot drive! (%s)\n", argv[curArg]);
            }
        }
        else if (strcmp(pszArg, "-bootmenu") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing argument for boot menu!\n");
            if (strlen(argv[curArg]) != 1 || *argv[curArg] < '0' || *argv[curArg] > '2')
                return SyntaxError("invalid argument for boot menu! (%s)\n", argv[curArg]);
            rc = VINF_SUCCESS;
            g_iBootMenu = *argv[curArg] - 0;
        }
        else if (strcmp(pszArg, "-m") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing argument for memory size!\n");
            rc = RTStrToUInt32Ex(argv[curArg], NULL, 0, &g_u32MemorySizeMB);
            if (VBOX_FAILURE(rc))
                return SyntaxError("bad memory size: %s (error %Vrc)\n",
                                   argv[curArg], rc);
        }
        else if (strcmp(pszArg, "-vram") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing argument for vram size!\n");
            rc = RTStrToUInt32Ex(argv[curArg], NULL, 0, &g_u32VRamSizeMB);
            if (VBOX_FAILURE(rc))
                return SyntaxError("bad video ram size: %s (error %Vrc)\n",
                                   argv[curArg], rc);
        }
        else if (strcmp(pszArg, "-fullscreen") == 0)
            fFullscreen = true;
        else if (strcmp(pszArg, "-nofstoggle") == 0)
            gfAllowFullscreenToggle = false;
        else if (strcmp(pszArg, "-nohostkey") == 0)
        {
            gHostKey = 0;
            gHostKeySym = 0;
        }
        else if (strcmp(pszArg, "-acpi") == 0)
            g_fACPI = true;
        else if (strcmp(pszArg, "-noacpi") == 0)
            g_fACPI = false;
        else if (strcmp(pszArg, "-ioapic") == 0)
            g_fIOAPIC = true;
        else if (strcmp(pszArg, "-noioapic") == 0)
            g_fIOAPIC = false;
        else if (strcmp(pszArg, "-audio") == 0)
            g_fAudio = true;
#ifdef VBOXBFE_WITH_USB
        else if (strcmp(pszArg, "-usb") == 0)
            g_fUSB = true;
#endif
        else if (strcmp(pszArg, "-hda") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing file name for first hard disk!\n");

            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                g_pszHdaFile = RTPathRealDup(argv[curArg]);
            if (!g_pszHdaFile)
                return SyntaxError("The path to the specified harddisk, '%s', could not be resolved.\n", argv[curArg]);
        }
        else if (strcmp(pszArg, "-hdb") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing file name for second hard disk!\n");

            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                g_pszHdbFile = RTPathRealDup(argv[curArg]);
            if (!g_pszHdbFile)
                return SyntaxError("The path to the specified harddisk, '%s', could not be resolved.\n", argv[curArg]);
        }
        else if (strcmp(pszArg, "-fda") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing file/device name for first floppy disk!\n");

            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                g_pszFdaFile = RTPathRealDup(argv[curArg]);
            if (!g_pszFdaFile)
                return SyntaxError("The path to the specified floppy disk, '%s', could not be resolved.\n", argv[curArg]);
        }
        else if (strcmp(pszArg, "-cdrom") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing file/device name for first hard disk!\n");

            /* resolve it. */
            if (RTPathExists(argv[curArg]))
                g_pszCdromFile = RTPathRealDup(argv[curArg]);
            if (!g_pszCdromFile)
                return SyntaxError("The path to the specified cdrom, '%s', could not be resolved.\n", argv[curArg]);
        }
#ifdef RT_OS_L4
        /* This is leaving a lot of dead code in the L4 version of course,
           but I don't think that that is a major problem.  We may even
           activate it sometime... */
        else if (   strncmp(pszArg, "-hifdev", 7) == 0
                 || strncmp(pszArg, "-nonetd", 7) == 0)
#else
        else if (   strncmp(pszArg, "-natdev", 7) == 0
                 || strncmp(pszArg, "-hifdev", 7) == 0
                 || strncmp(pszArg, "-nonetd", 7) == 0
                 || strncmp(pszArg, "-intnet", 7) == 0)
#endif
        {
            int i = networkArg2Index(pszArg, 7);
            if (i < 0)
                return 1;
            g_aNetDevs[i].enmType = !strncmp(pszArg, "-natdev", 7)
                                  ? BFENETDEV::NAT
                                  : !strncmp(pszArg, "-hifdev", 7)
                                  ? BFENETDEV::HIF
                                  : !strncmp(pszArg, "-intnet", 7)
                                  ? BFENETDEV::INTNET
                                  : BFENETDEV::NONE;

            /* The HIF device name / The Internal Network name. */
            g_aNetDevs[i].pszName = NULL;
            if (    g_aNetDevs[i].enmType == BFENETDEV::HIF
                ||  g_aNetDevs[i].enmType == BFENETDEV::INTNET)
            {
                if (curArg + 1 >= argc)
                    return SyntaxError(g_aNetDevs[i].enmType == BFENETDEV::HIF
                                       ? "The TAP network device name is missing! (%s)\n"
                                       : "The internal network name is missing! (%s)\n"
                                       , pszArg);
                g_aNetDevs[i].pszName = argv[++curArg];
            }

            /* The MAC address. */
            const char *pszMac;
            char szMacGen[MAC_STRING_LEN + 1];
            if ((curArg + 1 < argc) && (argv[curArg + 1][0] != '-'))
                pszMac = argv[++curArg];
            else
            {
                rc = GenerateMACAddress(szMacGen);
                if (RT_FAILURE(rc))
                    return SyntaxError("failed to generate a hardware address for network device %d (error %Vrc)\n",
                                       i, rc);
                pszMac = szMacGen;
            }
            if (strlen(pszMac) != MAC_STRING_LEN)
                return SyntaxError("The network MAC address has an invalid length: %s (%s)\n", pszMac, pszArg);
            for (unsigned j = 0; j < RT_ELEMENTS(g_aNetDevs[i].Mac.au8); j++)
            {
                char c1 = toupper(*pszMac++) - '0';
                if (c1 > 9)
                    c1 -= 7;
                char c2 = toupper(*pszMac++) - '0';
                if (c2 > 9)
                    c2 -= 7;
                if (c2 > 16 || c1 > 16)
                    return SyntaxError("Invalid MAC address: %s\n", argv[curArg]);
                g_aNetDevs[i].Mac.au8[j] = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
            }
        }
        else if (strncmp(pszArg, "-netsniff", 9) == 0)
        {
            int i = networkArg2Index(pszArg, 7);
            if (rc < 0)
                return 1;
            g_aNetDevs[i].fSniff = true;
            /** @todo filename */
        }
#ifdef RT_OS_LINUX
        else if (strncmp(pszArg, "-tapfd", 6) == 0)
        {
            int i = networkArg2Index(pszArg, 7);
            if (++curArg >= argc)
                return SyntaxError("missing argument for %s!\n", pszArg);
            rc = RTStrToInt32Ex(argv[curArg], NULL, 0, &g_aNetDevs[i].fd);
            if (VBOX_FAILURE(rc))
                return SyntaxError("bad tap file descriptor: %s (error %VRc)\n", argv[curArg], rc);
            g_aNetDevs[i].fHaveFd = true;
        }
#endif /* RT_OS_LINUX */
#ifdef VBOX_VRDP
        else if (strcmp(pszArg, "-vrdp") == 0)
        {
            // -vrdp might take a port number (positive).
            portVRDP = 0;       // indicate that it was encountered.
            if (curArg + 1 < argc && argv[curArg + 1][0] != '-')
            {
                rc = RTStrToInt32Ex(argv[curArg], NULL, 0, &portVRDP);
                if (VBOX_FAILURE(rc))
                    return SyntaxError("cannot vrpd port: %s (%VRc)\n", argv[curArg], rc);
                if (portVRDP < 0 || portVRDP >= 0x10000)
                    return SyntaxError("vrdp port number is out of range: %RI32\n", portVRDP);
            }
        }
#endif /* VBOX_VRDP */
#ifdef VBOX_SECURELABEL
        else if (strcmp(pszArg, "-securelabel") == 0)
        {
            fSecureLabel = true;
            LogFlow(("Secure labelling turned on\n"));
        }
        else if (strcmp(pszArg, "-seclabelfnt") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing font file name for secure label!\n");
            secureLabelFontFile = argv[curArg];
        }
        else if (strcmp(pszArg, "-seclabelsiz") == 0)
        {
            if (++curArg >= argc)
                return SyntaxError("missing font point size for secure label!\n");
            secureLabelPointSize = atoi(argv[curArg]);
        }
#endif
        else if (strcmp(pszArg, "-rellog") == 0)
            g_fReleaseLog = true;
        else if (strcmp(pszArg, "-norellog") == 0)
            g_fReleaseLog = false;
        else if (strcmp(pszArg, "-prealloc") == 0)
            g_fPreAllocRam = true;
#ifdef VBOXSDL_ADVANCED_OPTIONS
        else if (strcmp(pszArg, "-rawr0") == 0)
            g_fRawR0 = true;
        else if (strcmp(pszArg, "-norawr0") == 0)
            g_fRawR0 = false;
        else if (strcmp(pszArg, "-rawr3") == 0)
            g_fRawR3 = true;
        else if (strcmp(pszArg, "-norawr3") == 0)
            g_fRawR3 = false;
        else if (strcmp(pszArg, "-patm") == 0)
            g_fPATM = true;
        else if (strcmp(pszArg, "-nopatm") == 0)
            g_fPATM = false;
        else if (strcmp(pszArg, "-csam") == 0)
            g_fCSAM = true;
        else if (strcmp(pszArg, "-nocsam") == 0)
            g_fCSAM = false;
#endif /* VBOXSDL_ADVANCED_OPTIONS */
#ifdef RT_OS_L4
        else if (strcmp(pszArg, "-env") == 0)
            ++curArg;
#endif /* RT_OS_L4 */
        /* just show the help screen */
        else
        {
            SyntaxError("unrecognized argument '%s'\n", pszArg);
            show_usage();
            return 1;
        }
    }

    gMachineDebugger = new MachineDebugger();
    gStatus = new VMStatus();
    gKeyboard = new Keyboard();
    gMouse = new Mouse();
    gVMMDev = new VMMDev();
    gDisplay = new VMDisplay();
#if defined(USE_SDL)
    /* First console, then framebuffer!! */
    gConsole = new SDLConsole();
    gFramebuffer = new SDLFramebuffer();
#elif defined(RT_OS_L4)
    gConsole = new L4Console();
    gFramebuffer = new L4Framebuffer();
#else
#error "todo"
#endif
    if (!gConsole->initialized())
        goto leave;
    gDisplay->RegisterExternalFramebuffer(gFramebuffer);

    /* start with something in the titlebar */
    gConsole->updateTitlebar();

    /*
     * Start the VM execution thread. This has to be done
     * asynchronously as powering up can take some time
     * (accessing devices such as the host DVD drive). In
     * the meantime, we have to service the SDL event loop.
     */

    RTTHREAD thread;
    rc = RTThreadCreate(&thread, VMPowerUpThread, 0, 0, RTTHREADTYPE_MAIN_WORKER, 0, "PowerUp");
    if (VBOX_FAILURE(rc))
    {
        RTPrintf("Error: Thread creation failed with %d\n", rc);
        return -1;
    }

    /* loop until the powerup processing is done */
    do
    {
#if defined(RT_OS_LINUX) && defined(USE_SDL)
        if (   machineState == VMSTATE_CREATING
            || machineState == VMSTATE_LOADING)
        {
            int event = gConsole->eventWait();

            switch (event)
            {
            case CONEVENT_USR_SCREENRESIZE:
                LogFlow(("CONEVENT_USR_SCREENRESIZE\n"));
                gFramebuffer->resize();
                /* notify the display that the resize has been completed */
                gDisplay->ResizeCompleted();
                break;

            case CONEVENT_USR_QUIT:
                RTPrintf("Error: failed to power up VM! No error text available.\n");
                goto leave;
            }
        }
        else
#endif
            RTThreadSleep(1000);
    }
    while (   machineState == VMSTATE_CREATING
           || machineState == VMSTATE_LOADING);

    if (machineState == VMSTATE_TERMINATED)
        goto leave;

    /* did the power up succeed? */
    if (machineState != VMSTATE_RUNNING)
    {
        RTPrintf("Error: failed to power up VM! No error text available (rc = 0x%x state = %d)\n", rc, machineState);
        goto leave;
    }

    gConsole->updateTitlebar();

#ifdef RT_OS_L4
    /* The L4 console provides (currently) a fixed resolution. */
    if (g_u32VRamSizeMB * _1M >=   gFramebuffer->getHostXres() 
                          * gFramebuffer->getHostYres()
                          * (gDisplay->getBitsPerPixel() / 8))
        gDisplay->SetVideoModeHint(gFramebuffer->getHostXres(), gFramebuffer->getHostYres(), 0, 0);
#endif

    /*
     * Main event loop
     */
    LogFlow(("VBoxSDL: Entering big event loop\n"));

    while (1)
    {
        int event = gConsole->eventWait();

        switch (event)
        {
        case CONEVENT_NONE:
            /* Handled internally */
            break;

        case CONEVENT_QUIT:
        case CONEVENT_USR_QUIT:
            goto leave;

        case CONEVENT_SCREENUPDATE:
            /// @todo that somehow doesn't seem to work!
            gFramebuffer->repaint();
            break;

        case CONEVENT_USR_TITLEBARUPDATE:
            gConsole->updateTitlebar();
            break;

        case CONEVENT_USR_SCREENRESIZE:
        {
            LogFlow(("CONEVENT_USR_SCREENRESIZE\n"));
            gFramebuffer->resize();
            /* notify the display that the resize has been completed */
            gDisplay->ResizeCompleted();
            break;
        }

#ifdef VBOX_SECURELABEL
        case CONEVENT_USR_SECURELABELUPDATE:
        {
           /*
             * Query the new label text
             */
            Bstr key = VBOXSDL_SECURELABEL_EXTRADATA;
            Bstr label;
            gMachine->COMGETTER(ExtraData)(key, label.asOutParam());
            Utf8Str labelUtf8 = label;
            /*
             * Now update the label
             */
            gFramebuffer->setSecureLabelText(labelUtf8.raw());
            break;
        }
#endif /* VBOX_SECURELABEL */

        }

    }

leave:
    LogFlow(("Returning from main()!\n"));

    if (pVM)
    {
        /*
         * If get here because the guest terminated using ACPI off we don't have to
         * switch off the VM because we were notified via vmstateChangeCallback()
         * that this already happened. In any other case stop the VM before killing her.
         */
        if (machineState != VMSTATE_OFF)
        {
            /* Power off VM */
            PVMREQ pReq;
            rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)VMR3PowerOff, 1, pVM);
        }

        /* And destroy it */
        rc = VMR3Destroy(pVM);
        AssertRC(rc);
    }

    delete gFramebuffer;
    delete gConsole;
    delete gDisplay;
    delete gKeyboard;
    delete gMouse;
    delete gStatus;
    delete gMachineDebugger;

    RTLogFlush(NULL);
    return VBOX_FAILURE (rc) ? 1 : 0;
}



/**
 * VM state callback function. Called by the VMM
 * using its state machine states.
 *
 * Primarily used to handle VM initiated power off, suspend and state saving,
 * but also for doing termination completed work (VMSTATE_TERMINATE).
 *
 * In general this function is called in the context of the EMT.
 *
 * @todo machineState is set to VMSTATE_RUNNING before all devices have received power on events
 *       this can prematurely allow the main thread to enter the event loop
 *
 * @param   pVM         The VM handle.
 * @param   enmState    The new state.
 * @param   enmOldState The old state.
 * @param   pvUser      The user argument.
 */
static DECLCALLBACK(void) vmstateChangeCallback(PVM pVM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
{
    LogFlow(("vmstateChangeCallback: changing state from %d to %d\n", enmOldState, enmState));
    machineState = enmState;

    switch (enmState)
    {
        /*
         * The VM has terminated
         */
        case VMSTATE_OFF:
        {
            gConsole->eventQuit();
            break;
        }

        /*
         * The VM has been completely destroyed.
         *
         * Note: This state change can happen at two points:
         *       1) At the end of VMR3Destroy() if it was not called from EMT.
         *       2) At the end of vmR3EmulationThread if VMR3Destroy() was called by EMT.
         */
        case VMSTATE_TERMINATED:
        {
            break;
        }

        default: /* shut up gcc */
            break;
    }
}


/**
 * VM error callback function. Called by the various VM components.
 *
 * @param   pVM         The VM handle.
 * @param   pvUser      The user argument.
 * @param   rc          VBox status code.
 * @param   pszError    Error message format string.
 * @param   args        Error message arguments.
 * @thread EMT.
 */
DECLCALLBACK(void) setVMErrorCallback(PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL,
                                      const char *pszFormat, va_list args)
{
    /** @todo accessing shared resource without any kind of synchronization */
    if (VBOX_SUCCESS(rc))
        szError[0] = '\0';
    else
    {
        RTStrPrintf(szError, sizeof(szError), 
                    "%N!\nVBox status code: %d (%Vrc)", pszFormat, &args, rc, rc);
        RTPrintf("%s\n", szError);
    }
}


/**
 * VM Runtime error callback function. Called by the various VM components.
 *
 * @param   pVM         The VM handle.
 * @param   pvUser      The user argument.
 * @param   fFata       Wheather it is a fatal error or not.
 * @param   pszErrorId  Error ID string.
 * @param   pszError    Error message format string.
 * @param   args        Error message arguments.
 * @thread EMT.
 */
DECLCALLBACK(void) setVMRuntimeErrorCallback(PVM pVM, void *pvUser, bool fFatal,
                                             const char *pszErrorId,
                                             const char *pszFormat, va_list args)
{
    RTPrintf("%s: %s!\n%N!\n", fFatal ? "Error" : "Warning", pszErrorId, pszFormat, &args);
}


/** VM asynchronous operations thread */
DECLCALLBACK(int) VMPowerUpThread(RTTHREAD Thread, void *pvUser)
{
    int rc = VINF_SUCCESS;
    int rc2;

    /*
     * Setup the release log instance in current directory.
     */
    if (g_fReleaseLog)
    {
        static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
        static char szError[RTPATH_MAX + 128] = "";
        PRTLOGGER pLogger;
        rc2 = RTLogCreateEx(&pLogger, RTLOGFLAGS_PREFIX_TIME_PROG, "all",
                            "VBOX_RELEASE_LOG", ELEMENTS(s_apszGroups), s_apszGroups,
                            RTLOGDEST_FILE, szError, sizeof(szError), "./VBoxBFE.log");
        if (VBOX_SUCCESS(rc2))
        {
            /* some introductory information */
            RTTIMESPEC TimeSpec;
            char szNowUct[64];
            RTTimeSpecToString(RTTimeNow(&TimeSpec), szNowUct, sizeof(szNowUct));
            RTLogRelLogger(pLogger, 0, ~0U,
                           "VBoxBFE %s (%s %s) release log\n"
                           "Log opened %s\n",
                           VBOX_VERSION_STRING, __DATE__, __TIME__,
                           szNowUct);

            /* register this logger as the release logger */
            RTLogRelSetDefaultInstance(pLogger);
        }
        else
            RTPrintf("Could not open release log (%s)\n", szError);
    }

    /*
     * Start VM (also from saved state) and track progress
     */
    LogFlow(("VMPowerUp\n"));

    /*
     * Create empty VM.
     */
    rc = VMR3Create(setVMErrorCallback, NULL, vboxbfeConfigConstructor, NULL, &pVM);
    if (VBOX_FAILURE(rc))
    {
        RTPrintf("Error: VM creation failed with %Vrc.\n", rc);
        goto failure;
    }


    /*
     * Register VM state change handler
     */
    rc = VMR3AtStateRegister(pVM, vmstateChangeCallback, NULL);
    if (VBOX_FAILURE(rc))
    {
        RTPrintf("Error: VMR3AtStateRegister failed with %Vrc.\n", rc);
        goto failure;
    }

#ifdef VBOXBFE_WITH_USB
    /*
     * Capture USB devices.
     */
    if (g_fUSB)
    {
        gHostUSB = new HostUSB();
        gHostUSB->init(pVM);
    }
#endif /* VBOXBFE_WITH_USB */

#ifdef RT_OS_L4
    /* L4 console cannot draw a host cursor */
    gMouse->setHostCursor(false);
#else
    gMouse->setHostCursor(true);
#endif

    /*
     * Power on the VM (i.e. start executing).
     */
    if (VBOX_SUCCESS(rc))
    {
        PVMREQ pReq;
        rc = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)VMR3PowerOn, 1, pVM);
        if (VBOX_SUCCESS(rc))
        {
            rc = pReq->iStatus;
            AssertRC(rc);
            VMR3ReqFree(pReq);
        }
        else
            AssertMsgFailed(("VMR3PowerOn failed, rc=%Vrc\n", rc));
    }

    /*
     * On failure destroy the VM.
     */
    if (VBOX_FAILURE(rc))
        goto failure;

    return 0;

failure:
    if (pVM)
    {
        rc2 = VMR3Destroy(pVM);
        AssertRC(rc2);
        pVM = NULL;
    }
    machineState = VMSTATE_TERMINATED;

    return 0;
}

/**
 * Register the main drivers.
 *
 * @returns VBox status code.
 * @param   pCallbacks      Pointer to the callback table.
 * @param   u32Version      VBox version number.
 */
DECLCALLBACK(int) VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)
{
    int rc;

    LogFlow(("VBoxDriversRegister: u32Version=%#x\n", u32Version));
    AssertReleaseMsg(u32Version == VBOX_VERSION, ("u32Version=%#x VBOX_VERSION=%#x\n", u32Version, VBOX_VERSION));

    rc = pCallbacks->pfnRegister(pCallbacks, &Mouse::DrvReg);
    AssertRC(rc);
    if (VBOX_FAILURE(rc))
        return rc;
    rc = pCallbacks->pfnRegister(pCallbacks, &Keyboard::DrvReg);
    AssertRC(rc);
    if (VBOX_FAILURE(rc))
        return rc;

    rc = pCallbacks->pfnRegister(pCallbacks, &VMDisplay::DrvReg);
    AssertRC(rc);
    if (VBOX_FAILURE(rc))
        return rc;
    rc = pCallbacks->pfnRegister(pCallbacks, &VMMDev::DrvReg);
    AssertRC(rc);
    if (VBOX_FAILURE(rc))
        return rc;

    rc = pCallbacks->pfnRegister(pCallbacks, &VMStatus::DrvReg);
    if (VBOX_FAILURE(rc))
        return rc;

    return VINF_SUCCESS;
}


/**
 * Constructs the VMM configuration tree.
 *
 * @returns VBox status code.
 * @param   pVM     VM handle.
 */
static DECLCALLBACK(int) vboxbfeConfigConstructor(PVM pVM, void *pvUser)
{
    int rcAll = VINF_SUCCESS;
    int rc;

#define UPDATE_RC() do { if (VBOX_FAILURE(rc) && VBOX_SUCCESS(rcAll)) rcAll = rc; } while (0)

    /*
     * Root values.
     */
    PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
    rc = CFGMR3InsertString(pRoot,  "Name",           "Default VM");                UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "RamSize",        g_u32MemorySizeMB * _1M);     UPDATE_RC();
    if (g_fPreAllocRam)
    {
        rc = CFGMR3InsertInteger(pRoot, "RamPreAlloc",    1);                       UPDATE_RC();
    }
    rc = CFGMR3InsertInteger(pRoot, "TimerMillies",   10);                          UPDATE_RC();
#ifdef VBOXSDL_ADVANCED_OPTIONS
    rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled",   g_fRawR3);                    UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled",   g_fRawR0);                    UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "PATMEnabled",    g_fPATM);                     UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled",    g_fCSAM);                     UPDATE_RC();
#else
    rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled",   1);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled",   1);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "PATMEnabled",    1);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled",    1);                           UPDATE_RC();
#endif

    /*
     * PDM.
     */
    rc = PDMR3RegisterDrivers(pVM, VBoxDriversRegister);                            UPDATE_RC();

    /*
     * Devices
     */
    PCFGMNODE pDevices = NULL;
    rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);                             UPDATE_RC();
    /* device */
    PCFGMNODE pDev = NULL;
    PCFGMNODE pInst = NULL;
    PCFGMNODE pCfg = NULL;
    PCFGMNODE pLunL0 = NULL;
    PCFGMNODE pLunL1 = NULL;
    PCFGMNODE pDrv = NULL;

    /*
     * PC Arch.
     */
    rc = CFGMR3InsertNode(pDevices, "pcarch",         &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    /*
     * PC Bios.
     */
    rc = CFGMR3InsertNode(pDevices, "pcbios",         &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",              1);     /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "RamSize",        g_u32MemorySizeMB * _1M);     UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "BootDevice0",    pszBootDevice);               UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "BootDevice1",    "NONE");                      UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "BootDevice2",    "NONE");                      UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "BootDevice3",    "NONE");                      UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "HardDiskDevice", "piix3ide");                  UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "FloppyDevice",   "i82078");                    UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOAPIC",         g_fIOAPIC);                   UPDATE_RC();

    /* Default: no bios logo. */
    rc = CFGMR3InsertInteger(pCfg,  "FadeIn",         1);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "FadeOut",        0);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "LogoTime",       0);                           UPDATE_RC();
    rc = CFGMR3InsertString(pCfg,   "LogoFile",       "");                          UPDATE_RC();

    /* Boot menu */
    rc = CFGMR3InsertInteger(pCfg,  "ShowBootMenu",   g_iBootMenu);                 UPDATE_RC();

    /*
     * ACPI
     */
    if (g_fACPI)
    {
        rc = CFGMR3InsertNode(pDevices, "acpi",           &pDev);                   UPDATE_RC();
        rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                  UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "Trusted",        1);       /* boolean */   UPDATE_RC();
        rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "RamSize",        g_u32MemorySizeMB * _1M); UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "IOAPIC",         g_fIOAPIC);               UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    7);                       UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                       UPDATE_RC();

        rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "ACPIHost");              UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
    }

    /*
     * PCI bus.
     */
    rc = CFGMR3InsertNode(pDevices, "pci",            &pDev);       /* piix3 */     UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOAPIC",         g_fIOAPIC);                   UPDATE_RC();

    /*
     * DMA
     */
    rc = CFGMR3InsertNode(pDevices, "8237A",          &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();

    /*
     * PCI bus.
     */
    rc = CFGMR3InsertNode(pDevices, "pci",            &pDev);       /* piix3 */     UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    /*
     * PS/2 keyboard & mouse.
     */
    rc = CFGMR3InsertNode(pDevices, "pckbd",          &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                     UPDATE_RC();
    rc = CFGMR3InsertString(pLunL0, "Driver",         "KeyboardQueue");             UPDATE_RC();
    rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "QueueSize",      64);                          UPDATE_RC();

    rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pDrv);                       UPDATE_RC();
    rc = CFGMR3InsertString(pDrv,   "Driver",         "MainKeyboard");              UPDATE_RC();
    rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "Object",         (uintptr_t)gKeyboard);        UPDATE_RC();

    rc = CFGMR3InsertNode(pInst,    "LUN#1",          &pLunL0);                     UPDATE_RC();
    rc = CFGMR3InsertString(pLunL0, "Driver",         "MouseQueue");                UPDATE_RC();
    rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "QueueSize",      128);                         UPDATE_RC();

    rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pDrv);                       UPDATE_RC();
    rc = CFGMR3InsertString(pDrv,   "Driver",         "MainMouse");                 UPDATE_RC();
    rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "Object",         (uintptr_t)gMouse);           UPDATE_RC();


    /*
     * i82078 Floppy drive controller
     */
    rc = CFGMR3InsertNode(pDevices, "i82078",         &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);                           UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IRQ",            6);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "DMA",            2);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "MemMapped",      0 );                          UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOBase",         0x3f0);                       UPDATE_RC();

    /* Attach the status driver */
    rc = CFGMR3InsertNode(pInst,    "LUN#999",        &pLunL0);                     UPDATE_RC();
    rc = CFGMR3InsertString(pLunL0, "Driver",         "MainStatus");                UPDATE_RC();
    rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "papLeds",        (uintptr_t)&mapFDLeds[0]);    UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "First",          0);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "Last",           0);                           UPDATE_RC();

    if (g_pszFdaFile)
    {
        rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "Block");                 UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Type",           "Floppy 1.44");           UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "Mountable", 1);                            UPDATE_RC();

        rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pDrv);                   UPDATE_RC();
        rc = CFGMR3InsertString(pDrv,   "Driver",         "RawImage");              UPDATE_RC();
        rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Path",           g_pszFdaFile);            UPDATE_RC();
    }

    /*
     * i8254 Programmable Interval Timer And Dummy Speaker
     */
    rc = CFGMR3InsertNode(pDevices, "i8254",          &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
#ifdef DEBUG
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
#endif

    /*
     * i8259 Programmable Interrupt Controller.
     */
    rc = CFGMR3InsertNode(pDevices, "i8259",          &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    /*
     * Advanced Programmable Interrupt Controller.
     */
    rc = CFGMR3InsertNode(pDevices, "apic",           &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOAPIC",         g_fIOAPIC);                   UPDATE_RC();

    /*
     * I/O Advanced Programmable Interrupt Controller.
     */
    if (g_fIOAPIC)
    {
        rc = CFGMR3InsertNode(pDevices, "ioapic",         &pDev);                   UPDATE_RC();
        rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                  UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "Trusted",        1);       /* boolean */   UPDATE_RC();
        rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                   UPDATE_RC();
    }

    /*
     * RTC MC146818.
     */
    rc = CFGMR3InsertNode(pDevices, "mc146818",       &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    /*
     * Serial ports
     */
    rc = CFGMR3InsertNode(pDevices, "serial",         &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IRQ",            4);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOBase",         0x3f8);                       UPDATE_RC();

    rc = CFGMR3InsertNode(pDev,     "1",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IRQ",            3);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "IOBase",         0x2f8);                       UPDATE_RC();

    /*
     * VGA.
     */
    rc = CFGMR3InsertNode(pDevices, "vga",            &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    2);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                           UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "VRamSize",       g_u32VRamSizeMB * _1M);       UPDATE_RC();

#ifdef RT_OS_L4
    /* XXX hard-coded */
    rc = CFGMR3InsertInteger(pCfg,  "HeightReduction", 18);                         UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "CustomVideoModes", 1);                         UPDATE_RC();
    char szBuf[64];
    /* Tell the guest which is the ideal video mode to use */
    RTStrPrintf(szBuf, sizeof(szBuf), "%dx%dx%d",
                gFramebuffer->getHostXres(),
                gFramebuffer->getHostYres(),
                gFramebuffer->getHostBitsPerPixel());
    rc = CFGMR3InsertString(pCfg,   "CustomVideoMode1", szBuf);                     UPDATE_RC();
#endif

    rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                     UPDATE_RC();
    rc = CFGMR3InsertString(pLunL0, "Driver",         "MainDisplay");               UPDATE_RC();
    rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "Object",         (uintptr_t)gDisplay);         UPDATE_RC();

    /*
     * IDE (update this when the main interface changes)
     */
    rc = CFGMR3InsertNode(pDevices, "piix3ide",       &pDev); /* piix3 */           UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);     /* boolean */         UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    1);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  1);                           UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();

    if (g_pszHdaFile)
    {
        const char *szDriver;
        if (0 == strcmp(RTPathExt(g_pszHdaFile), ".vdi"))
            szDriver = "VBoxHDD";  /* .vdi */
        else
            szDriver = "VD";       /* .vmdk */

        rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "Block");                 UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Type",           "HardDisk");              UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "Mountable",      0);                       UPDATE_RC();

        rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pDrv);                   UPDATE_RC();
        rc = CFGMR3InsertString(pDrv,   "Driver",         szDriver);                UPDATE_RC();
        rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Path",           g_pszHdaFile);            UPDATE_RC();
    }

    if (g_pszHdbFile)
    {
        const char *szDriver;
        if (0 == strcmp(RTPathExt(g_pszHdbFile), ".vdi"))
            szDriver = "VBoxHDD";  /* .vdi */
        else
            szDriver = "VD";       /* .vmdk */

        rc = CFGMR3InsertNode(pInst,    "LUN#1",          &pLunL1);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL1, "Driver",         "Block");                 UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL1,   "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Type",           "HardDisk");              UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "Mountable",      0);                       UPDATE_RC();

        rc = CFGMR3InsertNode(pLunL1,   "AttachedDriver", &pDrv);                   UPDATE_RC();
        rc = CFGMR3InsertString(pDrv,   "Driver",         szDriver);                UPDATE_RC();
        rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Path",           g_pszHdbFile);            UPDATE_RC();
    }

    if (g_pszCdromFile)
    {
        // ASSUME: DVD drive is always attached to LUN#2 (i.e. secondary IDE master)
        rc = CFGMR3InsertNode(pInst,    "LUN#2",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "Block");                 UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Type",           "DVD");                   UPDATE_RC();
        rc = CFGMR3InsertInteger(pCfg,  "Mountable",      1);                       UPDATE_RC();

        rc = CFGMR3InsertNode(pLunL0,   "AttachedDriver", &pDrv);                   UPDATE_RC();
        rc = CFGMR3InsertString(pDrv,   "Driver",         "MediaISO");              UPDATE_RC();
        rc = CFGMR3InsertNode(pDrv,     "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertString(pCfg,   "Path",           g_pszCdromFile);          UPDATE_RC();
    }

    /*
     * Network adapters
     */
    rc = CFGMR3InsertNode(pDevices, "pcnet",          &pDev);                       UPDATE_RC();
    for (ULONG ulInstance = 0; ulInstance < NetworkAdapterCount; ulInstance++)
    {
        if (g_aNetDevs[ulInstance].enmType != BFENETDEV::NOT_CONFIGURED)
        {
            char szInstance[4];
            RTStrPrintf(szInstance, sizeof(szInstance), "%lu", ulInstance);
            rc = CFGMR3InsertNode(pDev, szInstance, &pInst);                        UPDATE_RC();
            rc = CFGMR3InsertInteger(pInst, "Trusted", 1);                          UPDATE_RC();
            rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",
                                             !ulInstance ? 3 : ulInstance - 1 + 8); UPDATE_RC();
            rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                   UPDATE_RC();
            rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);               UPDATE_RC();
            rc = CFGMR3InsertBytes(pCfg,    "MAC",            &g_aNetDevs[ulInstance].Mac, sizeof(PDMMAC));
                                                                                    UPDATE_RC();

            /*
             * Enable the packet sniffer if requested.
             */
            if (g_aNetDevs[ulInstance].fSniff)
            {
                /* insert the sniffer filter driver. */
                rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);         UPDATE_RC();
                rc = CFGMR3InsertString(pLunL0, "Driver",         "NetSniffer");    UPDATE_RC();
                rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);           UPDATE_RC();
                if (g_aNetDevs[ulInstance].pszSniff)
                {
                    rc = CFGMR3InsertString(pCfg,   "File", g_aNetDevs[ulInstance].pszSniff);
                                                                                    UPDATE_RC();
                }
            }

            /*
             * Create the driver config (if any).
             */
            if (g_aNetDevs[ulInstance].enmType != BFENETDEV::NONE)
            {
                if (g_aNetDevs[ulInstance].fSniff)
                {
                    rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL0);       UPDATE_RC();
                }
                else
                {
                    rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);                 UPDATE_RC();
                }
                rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);                     UPDATE_RC();
            }

            /*
             * Configure the driver.
             */
            if (g_aNetDevs[ulInstance].enmType == BFENETDEV::NAT)
            {
                rc = CFGMR3InsertString(pLunL0, "Driver", "NAT");                   UPDATE_RC();
                rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);                     UPDATE_RC();
                /* (Port forwarding goes here.) */
            }
            else if (g_aNetDevs[ulInstance].enmType == BFENETDEV::HIF)
            {
                rc = CFGMR3InsertString(pLunL0, "Driver", "HostInterface");         UPDATE_RC();
                rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);                     UPDATE_RC();

#if defined(RT_OS_LINUX)
                if (g_aNetDevs[ulInstance].fHaveFd)
                {
                    rc = CFGMR3InsertString(pCfg, "Device", g_aNetDevs[ulInstance].pszName);
                                                                                    UPDATE_RC();
                    rc = CFGMR3InsertInteger(pCfg, "FileHandle", g_aNetDevs[ulInstance].fd);
                                                                                    UPDATE_RC();
                }
                else
#endif
                {
#if defined (RT_OS_LINUX) || defined (RT_OS_L4)
                    /*
                     * Create/Open the TAP the device.
                     */
                    RTFILE tapFD;
                    rc = RTFileOpen(&tapFD, "/dev/net/tun",
                                    RTFILE_O_READWRITE | RTFILE_O_OPEN |
                                    RTFILE_O_DENY_NONE | RTFILE_O_INHERIT);
                    if (VBOX_FAILURE(rc))
                    {
                        FatalError("Failed to open /dev/net/tun: %Vrc\n", rc);
                        return rc;
                    }

                    struct ifreq IfReq;
                    memset(&IfReq, 0, sizeof(IfReq));
                    if (g_aNetDevs[ulInstance].pszName && g_aNetDevs[ulInstance].pszName[0])
                    {
                        size_t cch = strlen(g_aNetDevs[ulInstance].pszName);
                        if (cch >= sizeof(IfReq.ifr_name))
                        {
                            FatalError("HIF name too long for device #%d: %s\n",
                                       ulInstance + 1, g_aNetDevs[ulInstance].pszName);
                            return VERR_BUFFER_OVERFLOW;
                        }
                        memcpy(IfReq.ifr_name, g_aNetDevs[ulInstance].pszName, cch + 1);
                    }
                    else
                        strcpy(IfReq.ifr_name, "tun%d");
                    IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
                    rc = ioctl(tapFD, TUNSETIFF, &IfReq);
                    if (rc)
                    {
                        int rc2 = RTErrConvertFromErrno(errno);
                        FatalError("ioctl TUNSETIFF '%s' failed: errno=%d rc=%d (%Vrc)\n",
                                   IfReq.ifr_name, errno, rc, rc2);
                        return rc2;
                    }

                    rc = fcntl(tapFD, F_SETFL, O_NONBLOCK);
                    if (rc)
                    {
                        int rc2 = RTErrConvertFromErrno(errno);
                        FatalError("fcntl F_SETFL/O_NONBLOCK '%s' failed: errno=%d rc=%d (%Vrc)\n",
                                   IfReq.ifr_name, errno, rc, rc2);
                        return rc2;
                    }

                    rc = CFGMR3InsertString(pCfg, "Device", g_aNetDevs[ulInstance].pszName);        UPDATE_RC();
                    rc = CFGMR3InsertInteger(pCfg, "FileHandle", (RTFILE)tapFD);                    UPDATE_RC();

#elif defined(RT_OS_WINDOWS)
                    /*
                     * We need the GUID too here...
                     */
                    rc = CFGMR3InsertString(pCfg, "Device", g_aNetDevs[ulInstance].pszName);            UPDATE_RC();
                    rc = CFGMR3InsertString(pCfg, "HostInterfaceName", g_aNetDevs[ulInstance].pszName); UPDATE_RC();
                    rc = CFGMR3InsertString(pCfg, "GUID", g_aNetDevs[ulInstance].pszName /*pszGUID*/);  UPDATE_RC();


#else /* !RT_OS_LINUX && !RT_OS_L4 */
                    FatalError("Name based HIF devices not implemented yet for this host platform\n");
                    return VERR_NOT_IMPLEMENTED;
#endif
                }
            }
            else if (g_aNetDevs[ulInstance].enmType == BFENETDEV::INTNET)
            {
                /*
                 * Internal networking.
                 */
                rc = CFGMR3InsertString(pCfg, "Network", g_aNetDevs[ulInstance].pszName); UPDATE_RC();
            }
        }
    }

    /*
     * VMM Device
     */
    rc = CFGMR3InsertNode(pDevices, "VMMDev",         &pDev);                       UPDATE_RC();
    rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                      UPDATE_RC();
    rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                       UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "Trusted",        1);           /* boolean */   UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    4);                           UPDATE_RC();
    rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                           UPDATE_RC();

    /* the VMM device's Main driver */
    rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                     UPDATE_RC();
    rc = CFGMR3InsertString(pLunL0, "Driver",        "MainVMMDev");                 UPDATE_RC();
    rc = CFGMR3InsertNode(pLunL0,   "Config",        &pCfg);                        UPDATE_RC();
    rc = CFGMR3InsertInteger(pCfg,  "Object",        (uintptr_t)gVMMDev);           UPDATE_RC();

    /*
     * AC'97 ICH audio
     */
    if (g_fAudio)
    {
        rc = CFGMR3InsertNode(pDevices, "ichac97",        &pDev);                   UPDATE_RC();
        rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                  UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "Trusted",        1);       /* boolean */   UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    5);                       UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                       UPDATE_RC();
        rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);

        /* the Audio driver */
        rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "AUDIO");                 UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
#ifdef RT_OS_WINDOWS
        rc = CFGMR3InsertString(pCfg, "AudioDriver",      "winmm");                 UPDATE_RC();
#elif defined(RT_OS_DARWIN)
        rc = CFGMR3InsertString(pCfg, "AudioDriver",      "coreaudio");             UPDATE_RC();
#elif defined(RT_OS_LINUX)
        rc = CFGMR3InsertString(pCfg, "AudioDriver",      "oss");                   UPDATE_RC();
#elif defined(RT_OS_L4)
        rc = CFGMR3InsertString(pCfg, "AudioDriver",      "oss");                   UPDATE_RC();
#else /* portme */
        rc = CFGMR3InsertString(pCfg, "AudioDriver",      "none");                  UPDATE_RC();
#endif /* !RT_OS_WINDOWS */
    }

#ifdef VBOXBFE_WITH_USB
    /*
     * The USB Controller.
     */
    if (g_fUSB)
    {
        rc = CFGMR3InsertNode(pDevices, "usb-ohci",       &pDev);                   UPDATE_RC();
        rc = CFGMR3InsertNode(pDev,     "0",              &pInst);                  UPDATE_RC();
        rc = CFGMR3InsertNode(pInst,    "Config",         &pCfg);                   UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "Trusted",        1);       /* boolean */   UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo",    6);                       UPDATE_RC();
        rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo",  0);                       UPDATE_RC();

        rc = CFGMR3InsertNode(pInst,    "LUN#0",          &pLunL0);                 UPDATE_RC();
        rc = CFGMR3InsertString(pLunL0, "Driver",         "VUSBRootHub");           UPDATE_RC();
        rc = CFGMR3InsertNode(pLunL0,   "Config",         &pCfg);                   UPDATE_RC();
    }
#endif /* VBOXBFE_WITH_USB */

#undef UPDATE_RC
#undef UPDATE_RC

    VMR3AtRuntimeErrorRegister (pVM, setVMRuntimeErrorCallback, NULL);

    return rc;
}

Generated by  Doxygen 1.6.0   Back to index