Changeset 99528 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 26, 2023 6:07:05 AM (21 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevQemuFwCfg.cpp
r99215 r99528 74 74 #include <iprt/dir.h> 75 75 #include <iprt/file.h> 76 #include <iprt/mem.h> 76 77 #include <iprt/path.h> 77 78 #include <iprt/string.h> … … 79 80 #include <iprt/zero.h> 80 81 #include <iprt/zip.h> 82 #include <iprt/uuid.h> 81 83 82 84 #include "VBoxDD.h" … … 131 133 #define QEMU_FW_CFG_DMA_GET_CFG_ITEM(a_Control) ((uint16_t)((a_Control) >> 16)) 132 134 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" */ 133 137 134 138 /** @name Known config items. … … 160 164 #define QEMU_FW_CFG_ITEM_KERNEL_SETUP_DATA UINT16_C(0x0018) 161 165 #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) 162 169 /** @} */ 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 163 173 164 174 /** The size of the directory entry buffer we're using. */ … … 169 179 * Structures and Typedefs * 170 180 *********************************************************************************************************************************/ 181 182 /** 183 * RAM based framebuffer config. 184 */ 185 #pragma pack(1) 186 typedef 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() 202 AssertCompileSize(QEMURAMFBCONFIG, 28); 203 /** Pointer to a RAM based framebuffer config. */ 204 typedef QEMURAMFBCONFIG *PQEMURAMFBCONFIG; 205 /** Pointer to a const RAM based framebuffer config. */ 206 typedef 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 171 213 172 214 /** … … 189 231 190 232 233 /** 234 * QEMU firmware config file. 235 */ 236 typedef 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; 247 AssertCompileSize(QEMUFWCFGFILE, 64); 248 /** Pointer to a QEMU firmware config file. */ 249 typedef QEMUFWCFGFILE *PQEMUFWCFGFILE; 250 /** Pointer to a const QEMU firmware config file. */ 251 typedef const QEMUFWCFGFILE *PCQEMUFWCFGFILE; 252 253 254 /** Pointer to the QEMU firmware config device instance. */ 255 typedef struct DEVQEMUFWCFG *PDEVQEMUFWCFG; 191 256 /** Pointer to a const configuration item descriptor. */ 192 257 typedef const struct QEMUFWCFGITEM *PCQEMUFWCFGITEM; 193 258 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 */ 268 typedef DECLCALLBACKTYPE(int, FNQEMUFWCFGITEMSETUP,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem)); 269 /** Pointer to a FNQEMUFWCFGITEMSETUP() function. */ 270 typedef 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 */ 284 typedef 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. */ 287 typedef 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 */ 301 typedef 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. */ 304 typedef 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 */ 314 typedef DECLCALLBACKTYPE(void, FNQEMUFWCFGITEMCLEANUP,(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem)); 315 /** Pointer to a FNQEMUFWCFGITEMCLEANUP() function. */ 316 typedef FNQEMUFWCFGITEMCLEANUP *PFNQEMUFWCFGITEMCLEANUP; 231 317 232 318 … … 236 322 typedef struct QEMUFWCFGITEM 237 323 { 238 /** The config tiem value. */324 /** The config item value. */ 239 325 uint16_t uCfgItem; 240 326 /** Name of the item. */ … … 242 328 /** Optional CFGM key to lookup the content. */ 243 329 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; 275 339 } QEMUFWCFGITEM; 276 340 /** Pointer to a configuration item descriptor. */ 277 341 typedef QEMUFWCFGITEM *PQEMUFWCFGITEM; 278 342 343 344 /** 345 * A config file entry. 346 */ 347 typedef 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. */ 357 typedef QEMUFWCFGFILEENTRY *PQEMUFWCFGFILEENTRY; 358 /** Pointer to a const config file entry. */ 359 typedef const QEMUFWCFGFILEENTRY *PCQEMUFWCFGFILEENTRY; 360 361 362 /** 363 * QEMU firmware config instance data structure. 364 */ 365 typedef 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; 279 432 280 433 … … 309 462 static DECLCALLBACK(int) qemuFwCfgR3SetupFileDir(PDEVQEMUFWCFG pThis, PCQEMUFWCFGITEM pItem, uint32_t *pcbItem) 310 463 { 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); 314 468 return VINF_SUCCESS; 315 469 } … … 526 680 527 681 /** 682 * @interface_method_impl{QEMUFWCFGITEM,pfnRead, Reads data from the file directory.} 683 */ 684 static 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 /** 528 723 * @interface_method_impl{QEMUFWCFGITEM,pfnCleanup, Cleans up a VFS file type configuration item.} 529 724 */ … … 537 732 538 733 /** 734 * @interface_method_impl{QEMUFWCFGITEM,pfnSetup, Generic setup routine for file entries which don't have a dedicated setup routine.} 735 */ 736 static 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 /** 539 745 * Supported config items. 540 746 */ 541 747 static const QEMUFWCFGITEM g_aQemuFwCfgItems[] = 542 748 { 543 /** u16Selector pszItem pszCfgmKey pfnSetup pfnRead pfn Cleanup */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, qemuFwCfgR3Read Simple,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 } 555 761 }; 556 762 … … 587 793 qemuFwCfgR3ItemReset(pThis); 588 794 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; 606 828 } 607 829 … … 640 862 if (RT_SUCCESS(rc)) 641 863 { 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; 645 869 else if ( !pThis->pCfgItem 646 870 || !pThis->cbCfgItemLeft) … … 663 887 } 664 888 } 665 /* else: Assume Skip */889 /* else: Assume Skip or Write and ignore. */ 666 890 } 667 891 else 668 892 { 669 /* Read or skip. */893 /* Normal path. */ 670 894 RTGCPHYS GCPhysCur = DmaDesc.u64GCPhysBuf; 671 895 uint32_t cbLeft = RT_MIN(DmaDesc.u32Length, pThis->cbCfgItemLeft); 672 896 673 while ( RT_SUCCESS(rc) 674 && cbLeft) 897 if (DmaDesc.u32Ctrl & QEMU_FW_CFG_DMA_WRITE) 675 898 { 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) 683 901 { 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 } 693 942 } 694 943 } … … 841 1090 break; 842 1091 } 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; 843 1099 case QEU_FW_CFG_MMIO_OFF_SELECTOR: 844 case QEU_FW_CFG_MMIO_OFF_DMA:845 1100 /* Writeonly, ignore. */ 1101 rc = VINF_IOM_MMIO_UNUSED_00; 846 1102 break; 847 1103 default: … … 1230 1486 1231 1487 /** 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 */ 1499 static 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 */ 1544 static 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 */ 1587 static 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 */ 1624 static 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 */ 1635 static 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 */ 1653 static 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 */ 1666 static 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 */ 1677 static 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 */ 1688 static 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 */ 1700 static 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 */ 1711 static DECLCALLBACK(int) 1712 qemuFwCfgR3RamfbPortCopyRect(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 */ 1729 static 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 */ 1747 static 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 */ 1757 static 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 */ 1766 static 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 */ 1784 static 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 /** 1232 1795 * @interface_method_impl{PDMDEVREG,pfnReset} 1233 1796 */ … … 1248 1811 1249 1812 /** 1813 * @interface_method_impl{PDMDEVREG,pfnAttach} 1814 * 1815 * This is like plugging in the monitor after turning on the PC. 1816 */ 1817 static 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 */ 1884 static 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 /** 1250 1912 * @interface_method_impl{PDMDEVREG,pfnDestruct} 1251 1913 */ … … 1257 1919 qemuFwCfgR3ItemReset(pThis); 1258 1920 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); 1259 1932 1260 1933 if (pThis->hVfsFileInitrd != NIL_RTVFSFILE) … … 1285 1958 "|InitrdImage" 1286 1959 "|SetupImage" 1287 "|CmdLine", 1960 "|CmdLine" 1961 "|QemuRamfbSupport", 1288 1962 ""); 1289 1963 1290 bool fDmaEnabled = false; 1291 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DmaEnabled", &fDmaEnabled, false); 1964 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DmaEnabled", &pThis->fDmaEnabled, false); 1292 1965 if (RT_FAILURE(rc)) 1293 1966 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmaEnabled\"")); … … 1298 1971 pThis->pDevIns = pDevIns; 1299 1972 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); 1301 1974 pThis->GCPhysDma = 0; 1302 1975 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; 1303 1997 1304 1998 RTGCPHYS GCPhysMmioBase = 0; … … 1336 2030 1337 2031 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 } 1338 2064 1339 2065 rc = qemuFwCfgInitrdMaybeCreate(pThis); … … 1374 2100 /* .pfnSuspend = */ NULL, 1375 2101 /* .pfnResume = */ NULL, 1376 /* .pfnAttach = */ NULL,1377 /* .pfnDetach = */ NULL,2102 /* .pfnAttach = */ qemuFwCfgR3Attach, 2103 /* .pfnDetach = */ qemuFwCfgR3Detach, 1378 2104 /* .pfnQueryInterface = */ NULL, 1379 2105 /* .pfnInitComplete = */ NULL,
Note:
See TracChangeset
for help on using the changeset viewer.