VirtualBox

Changeset 99528 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Apr 26, 2023 6:07:05 AM (21 months ago)
Author:
vboxsync
Message:

Devies/DevQemuFwCfg: Implement support for the RAM based framebuffer, bugref:10431

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevQemuFwCfg.cpp

    r99215 r99528  
    7474#include <iprt/dir.h>
    7575#include <iprt/file.h>
     76#include <iprt/mem.h>
    7677#include <iprt/path.h>
    7778#include <iprt/string.h>
     
    7980#include <iprt/zero.h>
    8081#include <iprt/zip.h>
     82#include <iprt/uuid.h>
    8183
    8284#include "VBoxDD.h"
     
    131133#define QEMU_FW_CFG_DMA_GET_CFG_ITEM(a_Control)     ((uint16_t)((a_Control) >> 16))
    132134
     135/** The signature when reading the DMA address register and the DMA interace is enabled. */
     136#define QEMU_FW_CFG_DMA_ADDR_SIGNATURE              UINT64_C(0x51454d5520434647) /* "QEMU CFG" */
    133137
    134138/** @name Known config items.
     
    160164#define QEMU_FW_CFG_ITEM_KERNEL_SETUP_DATA          UINT16_C(0x0018)
    161165#define QEMU_FW_CFG_ITEM_FILE_DIR                   UINT16_C(0x0019)
     166
     167/** The first index for custom file based data. */
     168#define QEMU_FW_CFG_ITEM_FILE_USER_FIRST            UINT16_C(0x0020)
    162169/** @} */
     170
     171/** Maximum number of characters for a config item filename (without the zero terminator. */
     172#define QEMU_FW_CFG_ITEM_FILE_NAME_MAX              55
    163173
    164174/** The size of the directory entry buffer we're using. */
     
    169179*   Structures and Typedefs                                                                                                      *
    170180*********************************************************************************************************************************/
     181
     182/**
     183 * RAM based framebuffer config.
     184 */
     185#pragma pack(1)
     186typedef struct QEMURAMFBCONFIG
     187{
     188    /** Base physical address of the framebuffer. */
     189    uint64_t                    GCPhysRamfbBase;
     190    /** The FourCC code for the image format. */
     191    uint32_t                    u32FourCC;
     192    /** Flags for the framebuffer. */
     193    uint32_t                    u32Flags;
     194    /** Width of the framebuffer in pixels. */
     195    uint32_t                    cWidth;
     196    /** Height of the framebuffer in pixels. */
     197    uint32_t                    cHeight;
     198    /** Stride of the framebuffer in bytes. */
     199    uint32_t                    cbStride;
     200} QEMURAMFBCONFIG;
     201#pragma pack()
     202AssertCompileSize(QEMURAMFBCONFIG, 28);
     203/** Pointer to a RAM based framebuffer config. */
     204typedef QEMURAMFBCONFIG *PQEMURAMFBCONFIG;
     205/** Pointer to a const RAM based framebuffer config. */
     206typedef const QEMURAMFBCONFIG *PCQEMURAMFBCONFIG;
     207
     208/** The FourCC format code for RGB (+ ignored byte). */
     209#define QEMU_RAMFB_CFG_FORMAT   0x34325258 /* XRGB8888 */
     210/** Number of bytes per pixel. */
     211#define QEMU_RAMFB_CFG_BPP               4
     212
    171213
    172214/**
     
    189231
    190232
     233/**
     234 * QEMU firmware config file.
     235 */
     236typedef struct QEMUFWCFGFILE
     237{
     238    /** Size of the file in bytes. */
     239    uint32_t                    cbFile;
     240    /** The config selector item. */
     241    uint16_t                    uCfgItem;
     242    /** Reserved. */
     243    uint16_t                    u16Rsvd;
     244    /** The filename as an zero terminated ASCII string. */
     245    char                        szFilename[QEMU_FW_CFG_ITEM_FILE_NAME_MAX + 1];
     246} QEMUFWCFGFILE;
     247AssertCompileSize(QEMUFWCFGFILE, 64);
     248/** Pointer to a QEMU firmware config file. */
     249typedef QEMUFWCFGFILE *PQEMUFWCFGFILE;
     250/** Pointer to a const QEMU firmware config file. */
     251typedef const QEMUFWCFGFILE *PCQEMUFWCFGFILE;
     252
     253
     254/** Pointer to the QEMU firmware config device instance. */
     255typedef struct DEVQEMUFWCFG *PDEVQEMUFWCFG;
    191256/** Pointer to a const configuration item descriptor. */
    192257typedef const struct QEMUFWCFGITEM *PCQEMUFWCFGITEM;
    193258
    194 /**
    195  * QEMU firmware config instance data structure.
    196  */
    197 typedef struct DEVQEMUFWCFG
    198 {
    199     /** Pointer back to the device instance. */
    200     PPDMDEVINS                  pDevIns;
    201     /** The configuration handle. */
    202     PCFGMNODE                   pCfg;
    203     /** Pointer to the currently selected item. */
    204     PCQEMUFWCFGITEM             pCfgItem;
    205     /** Offset of the next byte to read from the start of the data item. */
    206     uint32_t                    offCfgItemNext;
    207     /** How many bytes are left for transfer. */
    208     uint32_t                    cbCfgItemLeft;
    209     /** Version register. */
    210     uint32_t                    u32Version;
    211     /** Guest physical address of the DMA descriptor. */
    212     RTGCPHYS                    GCPhysDma;
    213     /** VFS file of the on-the-fly created initramfs. */
    214     RTVFSFILE                   hVfsFileInitrd;
    215 
    216     /** Scratch buffer for config item specific data. */
    217     union
    218     {
    219         uint8_t                 u8;
    220         uint16_t                u16;
    221         uint32_t                u32;
    222         uint64_t                u64;
    223         /** VFS file handle. */
    224         RTVFSFILE               hVfsFile;
    225         /** Byte view. */
    226         uint8_t                 ab[8];
    227     } u;
    228 } DEVQEMUFWCFG;
    229 /** Pointer to the QEMU firmware config device instance. */
    230 typedef DEVQEMUFWCFG *PDEVQEMUFWCFG;
     259
     260/**
     261 * Setup callback for when the guest writes the selector.
     262 *
     263 * @returns VBox status code.
     264 * @param   pThis           The QEMU fw config device instance.
     265 * @param   pItem           Pointer to the selected item.
     266 * @param   pcbItem         Where to store the size of the item on success.
     267 */
     268typedef DECLCALLBACKTYPE(int, FNQEMUFWCFGITEMSETUP,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem));
     269/** Pointer to a FNQEMUFWCFGITEMSETUP() function. */
     270typedef FNQEMUFWCFGITEMSETUP *PFNQEMUFWCFGITEMSETUP;
     271
     272
     273/**
     274 * Read callback to return the data.
     275 *
     276 * @returns VBox status code.
     277 * @param   pThis           The QEMU fw config device instance.
     278 * @param   pItem           Pointer to the selected item.
     279 * @param   off             Where to start reading from.
     280 * @param   pvBuf           Where to store the read data.
     281 * @param   cbToRead        How much to read.
     282 * @param   pcbRead         Where to store the amount of bytes read.
     283 */
     284typedef DECLCALLBACKTYPE(int, FNQEMUFWCFGITEMREAD,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t off, void *pvBuf,
     285                                                   uint32_t cbToRead, uint32_t *pcbRead));
     286/** Pointer to a FNQEMUFWCFGITEMREAD() function. */
     287typedef FNQEMUFWCFGITEMREAD *PFNQEMUFWCFGITEMREAD;
     288
     289
     290/**
     291 * Write callback to receive data.
     292 *
     293 * @returns VBox status code.
     294 * @param   pThis           The QEMU fw config device instance.
     295 * @param   pItem           Pointer to the selected item.
     296 * @param   off             Where to start writing to.
     297 * @param   pvBuf           The data to write.
     298 * @param   cbToWrite       How much to write.
     299 * @param   pcbWritten      Where to store the amount of bytes written.
     300 */
     301typedef DECLCALLBACKTYPE(int, FNQEMUFWCFGITEMWRITE,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t off, const void *pvBuf,
     302                                                    uint32_t cbToWrite, uint32_t *pcbWritten));
     303/** Pointer to a FNQEMUFWCFGITEMWRITE() function. */
     304typedef FNQEMUFWCFGITEMWRITE *PFNQEMUFWCFGITEMWRITE;
     305
     306
     307/**
     308 * Cleans up any allocated resources when the item is de-selected.
     309 *
     310 * @returns nothing.
     311 * @param   pThis           The QEMU fw config device instance.
     312 * @param   pItem           Pointer to the selected item.
     313 */
     314typedef DECLCALLBACKTYPE(void, FNQEMUFWCFGITEMCLEANUP,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem));
     315/** Pointer to a FNQEMUFWCFGITEMCLEANUP() function. */
     316typedef FNQEMUFWCFGITEMCLEANUP *PFNQEMUFWCFGITEMCLEANUP;
    231317
    232318
     
    236322typedef struct QEMUFWCFGITEM
    237323{
    238     /** The config tiem value. */
     324    /** The config item value. */
    239325    uint16_t                    uCfgItem;
    240326    /** Name of the item. */
     
    242328    /** Optional CFGM key to lookup the content. */
    243329    const char                  *pszCfgmKey;
    244     /**
    245      * Setup callback for when the guest writes the selector.
    246      *
    247      * @returns VBox status code.
    248      * @param   pThis           The QEMU fw config device instance.
    249      * @param   pItem           Pointer to the selected item.
    250      * @param   pcbItem         Where to store the size of the item on success.
    251      */
    252     DECLCALLBACKMEMBER(int, pfnSetup, (PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem));
    253     /**
    254      * Read callback to return the data.
    255      *
    256      * @returns VBox status code.
    257      * @param   pThis           The QEMU fw config device instance.
    258      * @param   pItem           Pointer to the selected item.
    259      * @param   off             Where to start reading from.
    260      * @param   pvBuf           Where to store the read data.
    261      * @param   cbToRead        How much to read.
    262      * @param   pcbRead         Where to store the amount of bytes read.
    263      */
    264     DECLCALLBACKMEMBER(int, pfnRead, (PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t off, void *pvBuf,
    265                                       uint32_t cbToRead, uint32_t *pcbRead));
    266 
    267     /**
    268      * Cleans up any allocated resources when the item is de-selected.
    269      *
    270      * @returns nothing.
    271      * @param   pThis           The QEMU fw config device instance.
    272      * @param   pItem           Pointer to the selected item.
    273      */
    274     DECLCALLBACKMEMBER(void, pfnCleanup, (PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem));
     330
     331    /** Setup callback. */
     332    PFNQEMUFWCFGITEMSETUP       pfnSetup;
     333    /** Read callback. */
     334    PFNQEMUFWCFGITEMREAD        pfnRead;
     335    /** Write callback. */
     336    PFNQEMUFWCFGITEMWRITE       pfnWrite;
     337    /** Cleanup callback. */
     338    PFNQEMUFWCFGITEMCLEANUP     pfnCleanup;
    275339} QEMUFWCFGITEM;
    276340/** Pointer to a configuration item descriptor. */
    277341typedef QEMUFWCFGITEM *PQEMUFWCFGITEM;
    278342
     343
     344/**
     345 * A config file entry.
     346 */
     347typedef struct QEMUFWCFGFILEENTRY
     348{
     349    /** The config item structure. */
     350    QEMUFWCFGITEM                       Cfg;
     351    /** Size of the file in bytes. */
     352    uint32_t                            cbFile;
     353    /** The stored filename as an zero terminated ASCII string. */
     354    char                                szFilename[QEMU_FW_CFG_ITEM_FILE_NAME_MAX + 1];
     355} QEMUFWCFGFILEENTRY;
     356/** Pointer to a config file entry. */
     357typedef QEMUFWCFGFILEENTRY *PQEMUFWCFGFILEENTRY;
     358/** Pointer to a const config file entry. */
     359typedef const QEMUFWCFGFILEENTRY *PCQEMUFWCFGFILEENTRY;
     360
     361
     362/**
     363 * QEMU firmware config instance data structure.
     364 */
     365typedef struct DEVQEMUFWCFG
     366{
     367    /** Pointer back to the device instance. */
     368    PPDMDEVINS                          pDevIns;
     369    /** The configuration handle. */
     370    PCFGMNODE                           pCfg;
     371
     372    /** LUN\#0: The display port base interface. */
     373    PDMIBASE                            IBase;
     374    /** LUN\#0: The display port interface for the RAM based framebuffer if enabled. */
     375    PDMIDISPLAYPORT                     IPortRamfb;
     376
     377    /** Pointer to base interface of the driver - LUN#0. */
     378    R3PTRTYPE(PPDMIBASE)                pDrvBaseL0;
     379    /** Pointer to display connector interface of the driver - LUN#0. */
     380    R3PTRTYPE(PPDMIDISPLAYCONNECTOR)    pDrvL0;
     381
     382    /** Pointer to the currently selected item. */
     383    PCQEMUFWCFGITEM                     pCfgItem;
     384    /** Offset of the next byte to read from the start of the data item. */
     385    uint32_t                            offCfgItemNext;
     386    /** How many bytes are left for transfer. */
     387    uint32_t                            cbCfgItemLeft;
     388    /** Version register. */
     389    uint32_t                            u32Version;
     390    /** Guest physical address of the DMA descriptor. */
     391    RTGCPHYS                            GCPhysDma;
     392    /** VFS file of the on-the-fly created initramfs. */
     393    RTVFSFILE                           hVfsFileInitrd;
     394
     395    /** Pointer to the array of config file items. */
     396    PQEMUFWCFGFILEENTRY                 paCfgFiles;
     397    /** Number of entries in the config file item array. */
     398    uint32_t                            cCfgFiles;
     399    /** Number if entries allocated in the config file items array. */
     400    uint32_t                            cCfgFilesMax;
     401
     402    /** Critical section for synchronizing the RAM framebuffer access. */
     403    PDMCRITSECT                         CritSectRamfb;
     404    /** The refresh interval for the Ramfb support. */
     405    uint32_t                            cMilliesRefreshInterval;
     406    /** Refresh timer handle for the Ramfb support. */
     407    TMTIMERHANDLE                       hRamfbRefreshTimer;
     408    /** The current rambuffer config if enabled. */
     409    QEMURAMFBCONFIG                     RamfbCfg;
     410    /** Flag whether rendering the VRAM is enabled currently. */
     411    bool                                fRenderVRam;
     412    /** Flag whether the RAM based framebuffer device is enabled. */
     413    bool                                fRamfbSupported;
     414    /** Flag whether the DMA interface is available. */
     415    bool                                fDmaEnabled;
     416
     417    /** Scratch buffer for config item specific data. */
     418    union
     419    {
     420        uint8_t                         u8;
     421        uint16_t                        u16;
     422        uint32_t                        u32;
     423        uint64_t                        u64;
     424        /** VFS file handle. */
     425        RTVFSFILE                       hVfsFile;
     426        /** Firmware config file entry. */
     427        QEMUFWCFGFILE                   CfgFile;
     428        /** Byte view. */
     429        uint8_t                         ab[8];
     430    } u;
     431} DEVQEMUFWCFG;
    279432
    280433
     
    309462static DECLCALLBACK(int) qemuFwCfgR3SetupFileDir(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem)
    310463{
    311     RT_NOREF(pThis, pItem);
    312     memset(&pThis->u.ab[0], 0, sizeof(uint32_t)); /** @todo Implement */
    313     *pcbItem = sizeof(uint32_t);
     464    RT_NOREF(pItem);
     465    uint32_t cCfgFiles = RT_H2BE_U32(pThis->cCfgFiles);
     466    memcpy(&pThis->u.ab[0], &cCfgFiles, sizeof(cCfgFiles));
     467    *pcbItem = sizeof(uint32_t) + pThis->cCfgFiles * sizeof(QEMUFWCFGFILE);
    314468    return VINF_SUCCESS;
    315469}
     
    526680
    527681/**
     682 * @interface_method_impl{QEMUFWCFGITEM,pfnRead, Reads data from the file directory.}
     683 */
     684static DECLCALLBACK(int) qemuFwCfgR3ReadFileDir(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t off, void *pvBuf,
     685                                                uint32_t cbToRead, uint32_t *pcbRead)
     686{
     687    RT_NOREF(pItem);
     688
     689    /* The first 4 bytes are the number of entries following. */
     690    if (off < sizeof(uint32_t))
     691    {
     692        cbToRead = RT_MIN(cbToRead, sizeof(uint32_t) - off);
     693        memcpy(pvBuf, &pThis->u.ab[off], cbToRead);
     694        *pcbRead = cbToRead;
     695    }
     696    else
     697    {
     698        off -= sizeof(uint32_t);
     699
     700        /* The entries are static, so we can deduce the entry number from the offset. */
     701        uint32_t idxEntry = off / sizeof(*pThis->paCfgFiles);
     702        AssertReturn(idxEntry < pThis->cCfgFiles, VERR_INTERNAL_ERROR);
     703
     704        off %= sizeof(*pThis->paCfgFiles);
     705        cbToRead = RT_MIN(cbToRead, sizeof(pThis->u.CfgFile));
     706
     707        /* Setup the config file item. */
     708        PCQEMUFWCFGFILEENTRY pEntry = &pThis->paCfgFiles[idxEntry];
     709        pThis->u.CfgFile.cbFile   = RT_H2BE_U32(pEntry->cbFile);
     710        pThis->u.CfgFile.uCfgItem = RT_H2BE_U16(pEntry->Cfg.uCfgItem);
     711        pThis->u.CfgFile.u16Rsvd  = 0;
     712        strncpy(&pThis->u.CfgFile.szFilename[0], pEntry->Cfg.pszItem, sizeof(pThis->u.CfgFile.szFilename));
     713        pThis->u.CfgFile.szFilename[QEMU_FW_CFG_ITEM_FILE_NAME_MAX] = '\0';
     714
     715        memcpy(pvBuf, &pThis->u.ab[off], cbToRead);
     716        *pcbRead = cbToRead;
     717    }
     718    return VINF_SUCCESS;
     719}
     720
     721
     722/**
    528723 * @interface_method_impl{QEMUFWCFGITEM,pfnCleanup, Cleans up a VFS file type configuration item.}
    529724 */
     
    537732
    538733/**
     734 * @interface_method_impl{QEMUFWCFGITEM,pfnSetup, Generic setup routine for file entries which don't have a dedicated setup routine.}
     735 */
     736static DECLCALLBACK(int) qemuFwCfgR3SetupFileGeneric(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem)
     737{
     738    RT_NOREF(pItem);
     739    *pcbItem = pThis->paCfgFiles[pItem->uCfgItem - QEMU_FW_CFG_ITEM_FILE_USER_FIRST].cbFile;
     740    return VINF_SUCCESS;
     741}
     742
     743
     744/**
    539745 * Supported config items.
    540746 */
    541747static const QEMUFWCFGITEM g_aQemuFwCfgItems[] =
    542748{
    543     /** u16Selector                         pszItem         pszCfgmKey           pfnSetup                    pfnRead                         pfnCleanup */
    544     { QEMU_FW_CFG_ITEM_SIGNATURE,           "Signature",    NULL,                qemuFwCfgR3SetupSignature,  qemuFwCfgR3ReadSimple,          NULL                      },
    545     { QEMU_FW_CFG_ITEM_VERSION,             "Version",      NULL,                qemuFwCfgR3SetupVersion,    qemuFwCfgR3ReadSimple,          NULL                      },
    546     { QEMU_FW_CFG_ITEM_KERNEL_SIZE,         "KrnlSz",       "KernelImage",       qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL                      },
    547     { QEMU_FW_CFG_ITEM_KERNEL_DATA,         "KrnlDat",      "KernelImage",       qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         qemuFwCfgR3CleanupVfsFile },
    548     { QEMU_FW_CFG_ITEM_INITRD_SIZE,         "InitrdSz",     "InitrdImage",       qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL                      },
    549     { QEMU_FW_CFG_ITEM_KERNEL_DATA,         "InitrdDat",    "InitrdImage",       qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         qemuFwCfgR3CleanupVfsFile },
    550     { QEMU_FW_CFG_ITEM_KERNEL_SETUP_SIZE,   "SetupSz",      "SetupImage",        qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL                      },
    551     { QEMU_FW_CFG_ITEM_KERNEL_SETUP_DATA,   "SetupDat",     "SetupImage",        qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         qemuFwCfgR3CleanupVfsFile },
    552     { QEMU_FW_CFG_ITEM_CMD_LINE_SIZE,       "CmdLineSz",    "CmdLine",           qemuFwCfgR3SetupCfgmStrSz,  qemuFwCfgR3ReadSimple,          NULL                      },
    553     { QEMU_FW_CFG_ITEM_CMD_LINE_DATA,       "CmdLineDat",   "CmdLine",           qemuFwCfgR3SetupCfgmStr,    qemuFwCfgR3ReadStr,             NULL                      },
    554     { QEMU_FW_CFG_ITEM_FILE_DIR,            "FileDir",      NULL,                qemuFwCfgR3SetupFileDir,    qemuFwCfgR3ReadSimple,          NULL                      }
     749    /** u16Selector                         pszItem         pszCfgmKey           pfnSetup                    pfnRead                         pfnWrite                   pfnCleanup */
     750    { QEMU_FW_CFG_ITEM_SIGNATURE,           "Signature",    NULL,                qemuFwCfgR3SetupSignature,  qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     751    { QEMU_FW_CFG_ITEM_VERSION,             "Version",      NULL,                qemuFwCfgR3SetupVersion,    qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     752    { QEMU_FW_CFG_ITEM_KERNEL_SIZE,         "KrnlSz",       "KernelImage",       qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     753    { QEMU_FW_CFG_ITEM_KERNEL_DATA,         "KrnlDat",      "KernelImage",       qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         NULL,                      qemuFwCfgR3CleanupVfsFile },
     754    { QEMU_FW_CFG_ITEM_INITRD_SIZE,         "InitrdSz",     "InitrdImage",       qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     755    { QEMU_FW_CFG_ITEM_KERNEL_DATA,         "InitrdDat",    "InitrdImage",       qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         NULL,                      qemuFwCfgR3CleanupVfsFile },
     756    { QEMU_FW_CFG_ITEM_KERNEL_SETUP_SIZE,   "SetupSz",      "SetupImage",        qemuFwCfgR3SetupCfgmFileSz, qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     757    { QEMU_FW_CFG_ITEM_KERNEL_SETUP_DATA,   "SetupDat",     "SetupImage",        qemuFwCfgR3SetupCfgmFile,   qemuFwCfgR3ReadVfsFile,         NULL,                      qemuFwCfgR3CleanupVfsFile },
     758    { QEMU_FW_CFG_ITEM_CMD_LINE_SIZE,       "CmdLineSz",    "CmdLine",           qemuFwCfgR3SetupCfgmStrSz,  qemuFwCfgR3ReadSimple,          NULL,                      NULL                      },
     759    { QEMU_FW_CFG_ITEM_CMD_LINE_DATA,       "CmdLineDat",   "CmdLine",           qemuFwCfgR3SetupCfgmStr,    qemuFwCfgR3ReadStr,             NULL,                      NULL                      },
     760    { QEMU_FW_CFG_ITEM_FILE_DIR,            "FileDir",      NULL,                qemuFwCfgR3SetupFileDir,    qemuFwCfgR3ReadFileDir,         NULL,                      NULL                      }
    555761};
    556762
     
    587793    qemuFwCfgR3ItemReset(pThis);
    588794
    589     for (uint32_t i = 0; i < RT_ELEMENTS(g_aQemuFwCfgItems); i++)
    590     {
    591         PCQEMUFWCFGITEM pCfgItem = &g_aQemuFwCfgItems[i];
    592 
    593         if (pCfgItem->uCfgItem == uCfgItem)
    594         {
    595             uint32_t cbItem = 0;
    596             int rc = pCfgItem->pfnSetup(pThis, pCfgItem, &cbItem);
    597             if (RT_SUCCESS(rc))
    598             {
    599                 pThis->pCfgItem      = pCfgItem;
    600                 pThis->cbCfgItemLeft = cbItem;
    601                 return VINF_SUCCESS;
    602             }
    603 
    604             return rc;
    605         }
     795    PCQEMUFWCFGITEM pCfgItem = NULL;;
     796
     797    /* Check whether this is a file item. */
     798    if (uCfgItem >= QEMU_FW_CFG_ITEM_FILE_USER_FIRST)
     799    {
     800        uCfgItem -= QEMU_FW_CFG_ITEM_FILE_USER_FIRST;
     801        if (uCfgItem < pThis->cCfgFiles)
     802            pCfgItem = &pThis->paCfgFiles[uCfgItem].Cfg;
     803    }
     804    else
     805    {
     806        for (uint32_t i = 0; i < RT_ELEMENTS(g_aQemuFwCfgItems); i++)
     807        {
     808            pCfgItem = &g_aQemuFwCfgItems[i];
     809            if (pCfgItem->uCfgItem == uCfgItem)
     810                break;
     811        }
     812    }
     813
     814    if (pCfgItem)
     815    {
     816        uint32_t cbItem = 0;
     817        AssertPtrReturn(pCfgItem->pfnSetup, VERR_INVALID_STATE);
     818
     819        int rc = pCfgItem->pfnSetup(pThis, pCfgItem, &cbItem);
     820        if (RT_SUCCESS(rc))
     821        {
     822            pThis->pCfgItem      = pCfgItem;
     823            pThis->cbCfgItemLeft = cbItem;
     824            return VINF_SUCCESS;
     825        }
     826
     827        return rc;
    606828    }
    607829
     
    640862    if (RT_SUCCESS(rc))
    641863    {
    642         /* We don't support any writes right now. */
    643         if (DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_WRITE)
    644             rc = VERR_INVALID_PARAMETER;
     864        if (   (   DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_WRITE
     865                && !pThis->pCfgItem->pfnWrite)
     866            ||    (   DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_READ
     867                && !pThis->pCfgItem->pfnRead))
     868            rc = VERR_NOT_SUPPORTED;
    645869        else if (   !pThis->pCfgItem
    646870                 || !pThis->cbCfgItemLeft)
     
    663887                }
    664888            }
    665             /* else: Assume Skip */
     889            /* else: Assume Skip or Write and ignore. */
    666890        }
    667891        else
    668892        {
    669             /* Read or skip. */
     893            /* Normal path. */
    670894            RTGCPHYS GCPhysCur = DmaDesc.u64GCPhysBuf;
    671895            uint32_t cbLeft = RT_MIN(DmaDesc.u32Length, pThis->cbCfgItemLeft);
    672896
    673             while (   RT_SUCCESS(rc)
    674                    && cbLeft)
     897            if (DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_WRITE)
    675898            {
    676                 uint8_t abTmp[_1K];
    677                 uint32_t cbThisRead = RT_MIN(sizeof(abTmp), cbLeft);
    678                 uint32_t cbRead;
    679 
    680                 rc = pThis->pCfgItem->pfnRead(pThis, pThis->pCfgItem, pThis->offCfgItemNext, &abTmp[0],
    681                                                cbThisRead, &cbRead);
    682                 if (RT_SUCCESS(rc))
     899                while (   RT_SUCCESS(rc)
     900                       && cbLeft)
    683901                {
    684                     if (DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_READ)
    685                         PDMDevHlpPhysWriteMeta(pThis->pDevIns, GCPhysCur, &abTmp[0], cbRead);
    686                     /* else: Assume Skip */
    687 
    688                     cbLeft    -= cbRead;
    689                     GCPhysCur += cbRead;
    690 
    691                     pThis->offCfgItemNext += cbRead;
    692                     pThis->cbCfgItemLeft  -= cbRead;
     902                    uint8_t abTmp[_1K];
     903                    uint32_t cbThisWrite = RT_MIN(sizeof(abTmp), cbLeft);
     904                    uint32_t cbWritten;
     905
     906                    PDMDevHlpPhysReadMeta(pThis->pDevIns, GCPhysCur, &abTmp[0], cbThisWrite);
     907                    rc = pThis->pCfgItem->pfnWrite(pThis, pThis->pCfgItem, pThis->offCfgItemNext, &abTmp[0],
     908                                                   cbThisWrite, &cbWritten);
     909                    if (RT_SUCCESS(rc))
     910                    {
     911                        cbLeft    -= cbWritten;
     912                        GCPhysCur += cbWritten;
     913
     914                        pThis->offCfgItemNext += cbWritten;
     915                        pThis->cbCfgItemLeft  -= cbWritten;
     916                    }
     917                }
     918            }
     919            else
     920            {
     921                while (   RT_SUCCESS(rc)
     922                       && cbLeft)
     923                {
     924                    uint8_t abTmp[_1K];
     925                    uint32_t cbThisRead = RT_MIN(sizeof(abTmp), cbLeft);
     926                    uint32_t cbRead;
     927
     928                    rc = pThis->pCfgItem->pfnRead(pThis, pThis->pCfgItem, pThis->offCfgItemNext, &abTmp[0],
     929                                                   cbThisRead, &cbRead);
     930                    if (RT_SUCCESS(rc))
     931                    {
     932                        if (DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_READ)
     933                            PDMDevHlpPhysWriteMeta(pThis->pDevIns, GCPhysCur, &abTmp[0], cbRead);
     934                        /* else: Assume Skip */
     935
     936                        cbLeft    -= cbRead;
     937                        GCPhysCur += cbRead;
     938
     939                        pThis->offCfgItemNext += cbRead;
     940                        pThis->cbCfgItemLeft  -= cbRead;
     941                    }
    693942                }
    694943            }
     
    8411090            break;
    8421091        }
     1092        case QEU_FW_CFG_MMIO_OFF_DMA:
     1093            if (   cb == sizeof(uint64_t)
     1094                && pThis->fDmaEnabled)
     1095                *(uint64_t *)pv = RT_H2BE_U64(QEMU_FW_CFG_DMA_ADDR_SIGNATURE);
     1096            else
     1097                rc = VINF_IOM_MMIO_UNUSED_00;
     1098            break;
    8431099        case QEU_FW_CFG_MMIO_OFF_SELECTOR:
    844         case QEU_FW_CFG_MMIO_OFF_DMA:
    8451100            /* Writeonly, ignore. */
     1101            rc = VINF_IOM_MMIO_UNUSED_00;
    8461102            break;
    8471103        default:
     
    12301486
    12311487/**
     1488 * Registers a file item with the given name for consumption by the firmware.
     1489 *
     1490 * @returns VBox status code.
     1491 * @param   pThis               The QEMU fw config device instance.
     1492 * @param   pszFilename         The filename to use.
     1493 * @param   pvData              The data buffer to read from/write to.
     1494 * @param   pfnSetup            Setup callback - optional.
     1495 * @param   pfnRead             Read callback - optional.
     1496 * @param   pfnWrite            Write callback - optional.
     1497 * @param   pfnCleanup          Cleanup callback when the item gets de-selected - optional.
     1498 */
     1499static int qemuFwCfgR3FileRegister(PDEVQEMUFWCFG pThis, const char *pszFilename, uint32_t cbData,
     1500                                   PFNQEMUFWCFGITEMSETUP pfnSetup, PFNQEMUFWCFGITEMREAD pfnRead,
     1501                                   PFNQEMUFWCFGITEMWRITE pfnWrite, PFNQEMUFWCFGITEMCLEANUP pfnCleanup)
     1502{
     1503    AssertReturn(strlen(pszFilename) <= QEMU_FW_CFG_ITEM_FILE_NAME_MAX, VERR_FILENAME_TOO_LONG);
     1504
     1505    PQEMUFWCFGFILEENTRY pEntry = NULL;
     1506    if (pThis->cCfgFiles == pThis->cCfgFilesMax)
     1507    {
     1508        /* Grow the array. */
     1509        PQEMUFWCFGFILEENTRY paCfgFilesNew = (PQEMUFWCFGFILEENTRY)RTMemRealloc(pThis->paCfgFiles,
     1510                                                                              (pThis->cCfgFilesMax + 10) * sizeof(*pThis->paCfgFiles));
     1511        if (!paCfgFilesNew)
     1512            return VERR_NO_MEMORY;
     1513
     1514        pThis->paCfgFiles = paCfgFilesNew;
     1515        pThis->cCfgFilesMax += 10;
     1516    }
     1517
     1518    pEntry = &pThis->paCfgFiles[pThis->cCfgFiles];
     1519    pThis->cCfgFiles++;
     1520
     1521    pEntry->cbFile = cbData;
     1522    strncpy(&pEntry->szFilename[0], pszFilename, sizeof(pEntry->szFilename));
     1523    pEntry->Cfg.uCfgItem    = QEMU_FW_CFG_ITEM_FILE_USER_FIRST + pThis->cCfgFiles - 1;
     1524    pEntry->Cfg.pszItem     = &pEntry->szFilename[0];
     1525    pEntry->Cfg.pszCfgmKey  = NULL;
     1526    pEntry->Cfg.pfnSetup    = pfnSetup ? pfnSetup : qemuFwCfgR3SetupFileGeneric;
     1527    pEntry->Cfg.pfnRead     = pfnRead;
     1528    pEntry->Cfg.pfnWrite    = pfnWrite;
     1529    pEntry->Cfg.pfnCleanup  = pfnCleanup;
     1530    return VINF_SUCCESS;
     1531}
     1532
     1533
     1534/**
     1535 * RAM framebuffer config write callback.
     1536 *
     1537 * @param   pThis           The QEMU fw config device instance.
     1538 * @param   pItem           Pointer to the selected item.
     1539 * @param   off             Where to start writing to.
     1540 * @param   pvBuf           The data to write.
     1541 * @param   cbToWrite       How much to write.
     1542 * @param   pcbWritten      Where to store the amount of bytes written.
     1543 */
     1544static DECLCALLBACK(int) qemuFwCfgR3RamfbCfgWrite(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t off, const void *pvBuf,
     1545                                                  uint32_t cbToWrite, uint32_t *pcbWritten)
     1546{
     1547    RT_NOREF(pItem);
     1548
     1549    AssertReturn(!off && cbToWrite == sizeof(QEMURAMFBCONFIG), VERR_NOT_SUPPORTED);
     1550    *pcbWritten = cbToWrite;
     1551
     1552    PCQEMURAMFBCONFIG pRamfbCfg = (PCQEMURAMFBCONFIG)pvBuf;
     1553    if (   RT_BE2H_U32(pRamfbCfg->u32FourCC) != QEMU_RAMFB_CFG_FORMAT
     1554        || RT_BE2H_U32(pRamfbCfg->u32Flags) != 0)
     1555        return VERR_NOT_SUPPORTED;
     1556
     1557    int const rcLock = PDMDevHlpCritSectEnter(pThis->pDevIns, &pThis->CritSectRamfb, VERR_SEM_BUSY);
     1558    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pThis->pDevIns, &pThis->CritSectRamfb, rcLock);
     1559
     1560    pThis->RamfbCfg.GCPhysRamfbBase = RT_BE2H_U64(pRamfbCfg->GCPhysRamfbBase);
     1561    pThis->RamfbCfg.cbStride        = RT_BE2H_U32(pRamfbCfg->cbStride);
     1562    pThis->RamfbCfg.cWidth          = RT_BE2H_U32(pRamfbCfg->cWidth);
     1563    pThis->RamfbCfg.cHeight         = RT_BE2H_U32(pRamfbCfg->cHeight);
     1564    pThis->RamfbCfg.u32FourCC       = RT_BE2H_U32(pRamfbCfg->u32FourCC);
     1565    pThis->RamfbCfg.u32Flags        = RT_BE2H_U32(pRamfbCfg->u32Flags);
     1566
     1567    if (pThis->pDrvL0)
     1568    {
     1569        int rc = pThis->pDrvL0->pfnResize(pThis->pDrvL0, QEMU_RAMFB_CFG_BPP * 8, NULL /*pvVRAM*/,
     1570                                          pThis->RamfbCfg.cbStride,
     1571                                          pThis->RamfbCfg.cWidth,
     1572                                          pThis->RamfbCfg.cHeight);
     1573        AssertRC(rc);
     1574    }
     1575
     1576    PDMDevHlpCritSectLeave(pThis->pDevIns, &pThis->CritSectRamfb);
     1577
     1578    return VINF_SUCCESS;
     1579}
     1580
     1581
     1582/* -=-=-=-=-=- Ring 3: IDisplayPort -=-=-=-=-=- */
     1583
     1584/**
     1585 * @interface_method_impl{PDMIDISPLAYPORT,pfnUpdateDisplay}
     1586 */
     1587static DECLCALLBACK(int) qemuFwCfgR3RamfbPortUpdateDisplay(PPDMIDISPLAYPORT pInterface)
     1588{
     1589    PDEVQEMUFWCFG pThis = RT_FROM_MEMBER(pInterface, DEVQEMUFWCFG, IPortRamfb);
     1590
     1591    LogFlowFunc(("\n"));
     1592
     1593    int const rcLock = PDMDevHlpCritSectEnter(pThis->pDevIns, &pThis->CritSectRamfb, VERR_SEM_BUSY);
     1594    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pThis->pDevIns, &pThis->CritSectRamfb, rcLock);
     1595
     1596    if (   pThis->fRenderVRam
     1597        && pThis->RamfbCfg.GCPhysRamfbBase)
     1598    {
     1599        if (   pThis->RamfbCfg.cWidth == pThis->pDrvL0->cx
     1600            && pThis->RamfbCfg.cHeight == pThis->pDrvL0->cy
     1601            && pThis->RamfbCfg.cbStride == pThis->pDrvL0->cbScanline
     1602            && pThis->pDrvL0->pbData)
     1603        {
     1604            PDMDevHlpPhysReadUser(pThis->pDevIns, pThis->RamfbCfg.GCPhysRamfbBase, pThis->pDrvL0->pbData, pThis->RamfbCfg.cbStride * pThis->RamfbCfg.cHeight);
     1605            AssertPtr(pThis->pDrvL0);
     1606            pThis->pDrvL0->pfnUpdateRect(pThis->pDrvL0, 0, 0, pThis->RamfbCfg.cWidth, pThis->RamfbCfg.cHeight);
     1607        }
     1608        else
     1609            LogFlowFunc(("Framebuffer dimension mismatch ({%u, %u, %u} vs {%u, %u, %u})\n",
     1610                         pThis->RamfbCfg.cWidth, pThis->RamfbCfg.cHeight, pThis->RamfbCfg.cbStride,
     1611                         pThis->pDrvL0->cx, pThis->pDrvL0->cy, pThis->pDrvL0->cbScanline));
     1612    }
     1613    else
     1614        LogFlowFunc(("Rendering disabled or no RAM framebuffer set up\n"));
     1615
     1616    PDMDevHlpCritSectLeave(pThis->pDevIns, &pThis->CritSectRamfb);
     1617    return VINF_SUCCESS;
     1618}
     1619
     1620
     1621/**
     1622 * @interface_method_impl{PDMIDISPLAYPORT,pfnUpdateDisplayAll}
     1623 */
     1624static DECLCALLBACK(int) qemuFwCfgR3RamfbPortUpdateDisplayAll(PPDMIDISPLAYPORT pInterface, bool fFailOnResize)
     1625{
     1626    RT_NOREF(pInterface, fFailOnResize);
     1627    AssertReleaseFailed();
     1628    return VERR_NOT_IMPLEMENTED;
     1629}
     1630
     1631
     1632/**
     1633 * @interface_method_impl{PDMIDISPLAYPORT,pfnSetRefreshRate}
     1634 */
     1635static DECLCALLBACK(int) qemuFwCfgR3RamfbPortSetRefreshRate(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)
     1636{
     1637    PDEVQEMUFWCFG pThis = RT_FROM_MEMBER(pInterface, DEVQEMUFWCFG, IPortRamfb);
     1638
     1639    /*
     1640     * Update the interval, then restart or stop the timer.
     1641     */
     1642    ASMAtomicWriteU32(&pThis->cMilliesRefreshInterval, cMilliesInterval);
     1643
     1644    if (cMilliesInterval)
     1645        return PDMDevHlpTimerSetMillies(pThis->pDevIns, pThis->hRamfbRefreshTimer, cMilliesInterval);
     1646    return PDMDevHlpTimerStop(pThis->pDevIns, pThis->hRamfbRefreshTimer);
     1647}
     1648
     1649
     1650/**
     1651 * @interface_method_impl{PDMIDISPLAYPORT,pfnQueryVideoMode}
     1652 */
     1653static DECLCALLBACK(int) qemuFwCfgR3RamfbPortQueryVideoMode(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits, uint32_t *pcx, uint32_t *pcy)
     1654{
     1655    AssertReturn(pcBits, VERR_INVALID_PARAMETER);
     1656
     1657    RT_NOREF(pInterface, pcx, pcy);
     1658    AssertReleaseFailed();
     1659    return VERR_NOT_IMPLEMENTED;
     1660}
     1661
     1662
     1663/**
     1664 * @interface_method_impl{PDMIDISPLAYPORT,pfnTakeScreenshot}
     1665 */
     1666static DECLCALLBACK(int) qemuFwCfgR3RamfbPortTakeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t **ppbData, size_t *pcbData,
     1667                                                            uint32_t *pcx, uint32_t *pcy)
     1668{
     1669    RT_NOREF(pInterface, ppbData, pcbData, pcx, pcy);
     1670    return VERR_NOT_SUPPORTED;
     1671}
     1672
     1673
     1674/**
     1675 * @interface_method_impl{PDMIDISPLAYPORT,pfnFreeScreenshot}
     1676 */
     1677static DECLCALLBACK(void) qemuFwCfgR3RamfbPortFreeScreenshot(PPDMIDISPLAYPORT pInterface, uint8_t *pbData)
     1678{
     1679    NOREF(pInterface);
     1680    LogFlowFunc(("pbData=%p\n", pbData));
     1681    RTMemFree(pbData);
     1682}
     1683
     1684
     1685/**
     1686 * @interface_method_impl{PDMIDISPLAYPORT,pfnDisplayBlt}
     1687 */
     1688static DECLCALLBACK(int) qemuFwCfgR3RamfbPortDisplayBlt(PPDMIDISPLAYPORT pInterface, const void *pvData,
     1689                                                        uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
     1690{
     1691    RT_NOREF(pInterface, pvData, x, y, cx, cy);
     1692    AssertReleaseFailed();
     1693    return VERR_NOT_IMPLEMENTED;
     1694}
     1695
     1696
     1697/**
     1698 * @interface_method_impl{PDMIDISPLAYPORT,pfnUpdateDisplayRect}
     1699 */
     1700static DECLCALLBACK(void) qemuFwCfgR3RamfbPortUpdateDisplayRect(PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y,
     1701                                                                uint32_t cx, uint32_t cy)
     1702{
     1703    RT_NOREF(pInterface, x, y, cx, cy);
     1704    AssertReleaseFailed();
     1705}
     1706
     1707
     1708/**
     1709 * @interface_method_impl{PDMIDISPLAYPORT,pfnCopyRect}
     1710 */
     1711static DECLCALLBACK(int)
     1712qemuFwCfgR3RamfbPortCopyRect(PPDMIDISPLAYPORT pInterface,
     1713                             uint32_t cx, uint32_t cy,
     1714                             const uint8_t *pbSrc, int32_t xSrc, int32_t ySrc, uint32_t cxSrc, uint32_t cySrc,
     1715                             uint32_t cbSrcLine, uint32_t cSrcBitsPerPixel,
     1716                             uint8_t *pbDst, int32_t xDst, int32_t yDst, uint32_t cxDst, uint32_t cyDst,
     1717                             uint32_t cbDstLine, uint32_t cDstBitsPerPixel)
     1718{
     1719    RT_NOREF(pInterface, cx, cy, pbSrc, xSrc, ySrc, cxSrc, cySrc, cbSrcLine, cSrcBitsPerPixel, pbDst, xDst, yDst, cxDst, cyDst,
     1720             cbDstLine, cDstBitsPerPixel);
     1721    AssertReleaseFailed();
     1722    return VINF_SUCCESS;
     1723}
     1724
     1725
     1726/**
     1727 * @interface_method_impl{PDMIDISPLAYPORT,pfnSetRenderVRAM}
     1728 */
     1729static DECLCALLBACK(void) qemuFwCfgR3RamfbPortSetRenderVRAM(PPDMIDISPLAYPORT pInterface, bool fRender)
     1730{
     1731    PDEVQEMUFWCFG pThis = RT_FROM_MEMBER(pInterface, DEVQEMUFWCFG, IPortRamfb);
     1732
     1733    LogFlowFunc(("fRender = %d\n", fRender));
     1734
     1735    int const rcLock = PDMDevHlpCritSectEnter(pThis->pDevIns, &pThis->CritSectRamfb, VERR_SEM_BUSY);
     1736    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pThis->pDevIns, &pThis->CritSectRamfb, rcLock);
     1737
     1738    pThis->fRenderVRam = fRender;
     1739
     1740    PDMDevHlpCritSectLeave(pThis->pDevIns, &pThis->CritSectRamfb);
     1741}
     1742
     1743
     1744/**
     1745 * @interface_method_impl{PDMIDISPLAYPORT,pfnReportHostCursorCapabilities}
     1746 */
     1747static DECLCALLBACK(void) qemuFwCfgR3RamfbPortReportHostCursorCapabilities(PPDMIDISPLAYPORT pInterface, bool fSupportsRenderCursor,
     1748                                                                           bool fSupportsMoveCursor)
     1749{
     1750    RT_NOREF(pInterface, fSupportsRenderCursor, fSupportsMoveCursor);
     1751}
     1752
     1753
     1754/**
     1755 * @interface_method_impl{PDMIDISPLAYPORT,pfnReportHostCursorPosition}
     1756 */
     1757static DECLCALLBACK(void) qemuFwCfgR3RamfbPortReportHostCursorPosition(PPDMIDISPLAYPORT pInterface, uint32_t x, uint32_t y, bool fOutOfRange)
     1758{
     1759    RT_NOREF(pInterface, x, y, fOutOfRange);
     1760}
     1761
     1762
     1763/**
     1764 * @callback_method_impl{FNTMTIMERDEV, VGA Refresh Timer}
     1765 */
     1766static DECLCALLBACK(void) qemuFwCfgR3RamfbTimerRefresh(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
     1767{
     1768    PDEVQEMUFWCFG pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVQEMUFWCFG);
     1769    RT_NOREF(pvUser);
     1770
     1771    if (pThis->pDrvL0)
     1772        pThis->pDrvL0->pfnRefresh(pThis->pDrvL0);
     1773
     1774    if (pThis->cMilliesRefreshInterval)
     1775        PDMDevHlpTimerSetMillies(pDevIns, hTimer, pThis->cMilliesRefreshInterval);
     1776}
     1777
     1778
     1779/* -=-=-=-=-=- Ring 3: IBase -=-=-=-=-=- */
     1780
     1781/**
     1782 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
     1783 */
     1784static DECLCALLBACK(void *) qemuFwCfgR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     1785{
     1786    PDEVQEMUFWCFG pThis = RT_FROM_MEMBER(pInterface, DEVQEMUFWCFG, IBase);
     1787    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
     1788    if (pThis->fRamfbSupported)
     1789        PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYPORT, &pThis->IPortRamfb);
     1790    return NULL;
     1791}
     1792
     1793
     1794/**
    12321795 * @interface_method_impl{PDMDEVREG,pfnReset}
    12331796 */
     
    12481811
    12491812/**
     1813 * @interface_method_impl{PDMDEVREG,pfnAttach}
     1814 *
     1815 * This is like plugging in the monitor after turning on the PC.
     1816 */
     1817static DECLCALLBACK(int)  qemuFwCfgR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
     1818{
     1819    PDEVQEMUFWCFG pThis = PDMDEVINS_2_DATA(pDevIns, PDEVQEMUFWCFG);
     1820
     1821    AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
     1822                    ("QEMU RAM framebuffer device does not support hotplugging\n"),
     1823                    VERR_INVALID_PARAMETER);
     1824
     1825    switch (iLUN)
     1826    {
     1827        /* LUN #0: Display port. */
     1828        case 0:
     1829        {
     1830            AssertLogRelMsgReturn(pThis->fRamfbSupported,
     1831                                  ("QemuFwCfg: Trying to attach a display without the RAM framebuffer support being enabled!\n"),
     1832                                  VERR_NOT_SUPPORTED);
     1833
     1834            int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &pThis->pDrvBaseL0, "Display Port");
     1835            if (RT_SUCCESS(rc))
     1836            {
     1837                pThis->pDrvL0 = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBaseL0, PDMIDISPLAYCONNECTOR);
     1838                if (pThis->pDrvL0)
     1839                {
     1840                    /* pThis->pDrvL0->pbData can be NULL when there is no framebuffer. */
     1841                    if (    pThis->pDrvL0->pfnRefresh
     1842                        &&  pThis->pDrvL0->pfnResize
     1843                        &&  pThis->pDrvL0->pfnUpdateRect)
     1844                        rc = VINF_SUCCESS;
     1845                    else
     1846                    {
     1847                        Assert(pThis->pDrvL0->pfnRefresh);
     1848                        Assert(pThis->pDrvL0->pfnResize);
     1849                        Assert(pThis->pDrvL0->pfnUpdateRect);
     1850                        pThis->pDrvL0     = NULL;
     1851                        pThis->pDrvBaseL0 = NULL;
     1852                        rc = VERR_INTERNAL_ERROR;
     1853                    }
     1854                }
     1855                else
     1856                {
     1857                    AssertMsgFailed(("LUN #0 doesn't have a display connector interface! rc=%Rrc\n", rc));
     1858                    pThis->pDrvBaseL0 = NULL;
     1859                    rc = VERR_PDM_MISSING_INTERFACE;
     1860                }
     1861            }
     1862            else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     1863            {
     1864                Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
     1865                rc = VINF_SUCCESS;
     1866            }
     1867            else
     1868                AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
     1869            return rc;
     1870        }
     1871
     1872        default:
     1873            AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
     1874            return VERR_PDM_NO_SUCH_LUN;
     1875    }
     1876}
     1877
     1878
     1879/**
     1880 * @interface_method_impl{PDMDEVREG,pfnDetach}
     1881 *
     1882 * This is like unplugging the monitor while the PC is still running.
     1883 */
     1884static DECLCALLBACK(void)  qemuFwCfgR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
     1885{
     1886    PDEVQEMUFWCFG pThis = PDMDEVINS_2_DATA(pDevIns, PDEVQEMUFWCFG);
     1887    AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG, ("QEMU RAM framebuffer device does not support hotplugging\n"));
     1888    RT_NOREF(fFlags);
     1889
     1890    /*
     1891     * Reset the interfaces and update the controller state.
     1892     */
     1893    switch (iLUN)
     1894    {
     1895        /* LUN #0: Display port. */
     1896        case 0:
     1897            AssertLogRelMsg(pThis->fRamfbSupported,
     1898                            ("QemuFwCfg: Trying to detach a display without the RAM framebuffer support being enabled!\n"));
     1899
     1900            pThis->pDrvL0     = NULL;
     1901            pThis->pDrvBaseL0 = NULL;
     1902            break;
     1903
     1904        default:
     1905            AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
     1906            break;
     1907    }
     1908}
     1909
     1910
     1911/**
    12501912 * @interface_method_impl{PDMDEVREG,pfnDestruct}
    12511913 */
     
    12571919    qemuFwCfgR3ItemReset(pThis);
    12581920    pThis->GCPhysDma = 0;
     1921
     1922    if (pThis->paCfgFiles)
     1923    {
     1924        Assert(pThis->cCfgFiles && pThis->cCfgFilesMax);
     1925        RTMemFree(pThis->paCfgFiles);
     1926        pThis->paCfgFiles   = NULL;
     1927        pThis->cCfgFiles    = 0;
     1928        pThis->cCfgFilesMax = 0;
     1929    }
     1930    else
     1931        Assert(!pThis->cCfgFiles && !pThis->cCfgFilesMax);
    12591932
    12601933    if (pThis->hVfsFileInitrd != NIL_RTVFSFILE)
     
    12851958                                           "|InitrdImage"
    12861959                                           "|SetupImage"
    1287                                            "|CmdLine",
     1960                                           "|CmdLine"
     1961                                           "|QemuRamfbSupport",
    12881962                                           "");
    12891963
    1290     bool fDmaEnabled = false;
    1291     int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DmaEnabled", &fDmaEnabled, false);
     1964    int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DmaEnabled", &pThis->fDmaEnabled, false);
    12921965    if (RT_FAILURE(rc))
    12931966        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmaEnabled\""));
     
    12981971    pThis->pDevIns        = pDevIns;
    12991972    pThis->pCfg           = pCfg;
    1300     pThis->u32Version     = QEMU_FW_CFG_VERSION_LEGACY | (fDmaEnabled ? QEMU_FW_CFG_VERSION_DMA : 0);
     1973    pThis->u32Version     = QEMU_FW_CFG_VERSION_LEGACY | (pThis->fDmaEnabled ? QEMU_FW_CFG_VERSION_DMA : 0);
    13011974    pThis->GCPhysDma      = 0;
    13021975    pThis->hVfsFileInitrd = NIL_RTVFSFILE;
     1976    pThis->paCfgFiles     = NULL;
     1977    pThis->cCfgFiles      = 0;
     1978    pThis->cCfgFilesMax   = 0;
     1979
     1980    pThis->IBase.pfnQueryInterface                      = qemuFwCfgR3PortQueryInterface;
     1981
     1982    pThis->IPortRamfb.pfnUpdateDisplay                  = qemuFwCfgR3RamfbPortUpdateDisplay;
     1983    pThis->IPortRamfb.pfnUpdateDisplayAll               = qemuFwCfgR3RamfbPortUpdateDisplayAll;
     1984    pThis->IPortRamfb.pfnQueryVideoMode                 = qemuFwCfgR3RamfbPortQueryVideoMode;
     1985    pThis->IPortRamfb.pfnSetRefreshRate                 = qemuFwCfgR3RamfbPortSetRefreshRate;
     1986    pThis->IPortRamfb.pfnTakeScreenshot                 = qemuFwCfgR3RamfbPortTakeScreenshot;
     1987    pThis->IPortRamfb.pfnFreeScreenshot                 = qemuFwCfgR3RamfbPortFreeScreenshot;
     1988    pThis->IPortRamfb.pfnDisplayBlt                     = qemuFwCfgR3RamfbPortDisplayBlt;
     1989    pThis->IPortRamfb.pfnUpdateDisplayRect              = qemuFwCfgR3RamfbPortUpdateDisplayRect;
     1990    pThis->IPortRamfb.pfnCopyRect                       = qemuFwCfgR3RamfbPortCopyRect;
     1991    pThis->IPortRamfb.pfnSetRenderVRAM                  = qemuFwCfgR3RamfbPortSetRenderVRAM;
     1992    pThis->IPortRamfb.pfnSetViewport                    = NULL;
     1993    pThis->IPortRamfb.pfnReportMonitorPositions         = NULL;
     1994    pThis->IPortRamfb.pfnSendModeHint                   = NULL;
     1995    pThis->IPortRamfb.pfnReportHostCursorCapabilities   = qemuFwCfgR3RamfbPortReportHostCursorCapabilities;
     1996    pThis->IPortRamfb.pfnReportHostCursorPosition       = qemuFwCfgR3RamfbPortReportHostCursorPosition;
    13031997
    13041998    RTGCPHYS GCPhysMmioBase = 0;
     
    13362030
    13372031    qemuFwCfgR3ItemReset(pThis);
     2032
     2033    /* Setup the RAM based framebuffer support if configured. */
     2034    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "QemuRamfbSupport", &pThis->fRamfbSupported, false);
     2035    if (RT_FAILURE(rc))
     2036        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"QemuRamfbSupport\""));
     2037
     2038    if (pThis->fRamfbSupported)
     2039    {
     2040        LogRel(("QemuFwCfg: RAM based framebuffer support enabled\n"));
     2041        if (!pThis->fDmaEnabled)
     2042            return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER, N_("Configuration error: Enabling \"QemuRamfbSupport\" requires \"DmaEnabled\""));
     2043
     2044        /* Critical section for synchronizing access. */
     2045        rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSectRamfb, RT_SRC_POS, "Ramfb#%u", iInstance);
     2046        AssertRCReturn(rc, rc);
     2047
     2048        /*
     2049         * Create the refresh timer.
     2050         */
     2051        rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_REAL, qemuFwCfgR3RamfbTimerRefresh, NULL,
     2052                                  TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0, "Ramfb Refresh", &pThis->hRamfbRefreshTimer);
     2053        AssertRCReturn(rc, rc);
     2054
     2055        /* Register a config file item and attach the driver below us. */
     2056        rc = qemuFwCfgR3Attach(pDevIns, 0 /* display LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
     2057        AssertRCReturn(rc, rc);
     2058
     2059        rc = qemuFwCfgR3FileRegister(pThis, "etc/ramfb", sizeof(pThis->RamfbCfg),
     2060                                     NULL /* pfnSetup */, NULL /*pfnRead*/,
     2061                                     qemuFwCfgR3RamfbCfgWrite, NULL /*pfnCleanup*/);
     2062        AssertRCReturn(rc, rc);
     2063    }
    13382064
    13392065    rc = qemuFwCfgInitrdMaybeCreate(pThis);
     
    13742100    /* .pfnSuspend = */             NULL,
    13752101    /* .pfnResume = */              NULL,
    1376     /* .pfnAttach = */              NULL,
    1377     /* .pfnDetach = */              NULL,
     2102    /* .pfnAttach = */              qemuFwCfgR3Attach,
     2103    /* .pfnDetach = */              qemuFwCfgR3Detach,
    13782104    /* .pfnQueryInterface = */      NULL,
    13792105    /* .pfnInitComplete = */        NULL,
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette