解決qemu虛擬機無法設置分辨率的問題

問題描述:
在虛擬機中進行修改分辨率測試,結果如下:
在win7中測試設置ok。
在Centos7、Ubuntu16.04、Ubuntu18.04中測試均不行。

系統中設置分辨率也只有win7有效,其餘均無效,懷疑是QXL驅動問題。

問題排查分析如下:

查看日誌中出現如下報錯
Jul 2 15:22:28 Ubuntu1604 kernel: [ 6288.266180] qxl 0000:00:02.0: object_init failed for (4104192, 0x00000002)
Jul 2 15:22:28 Ubuntu1604 kernel: [ 6288.266190] [drm:qxl_gem_object_create [qxl]] ERROR Failed to allocate GEM object (4101120, 2, 4096, -12)
Jul 2 15:22:28 Ubuntu1604 kernel: [ 6288.266194] [drm:qxl_alloc_surf_ioctl [qxl]] ERROR qxl_alloc_surf_ioctl: failed to create gem ret=-12

首先對Linux中分辨率設置執行流程進行分析:
1)xorg自動識別pci顯卡並使用相應驅動
xorg-server首先會獲取到該pci設備的vendor_id,之後對其進行判斷,當其值爲0x1b36時判斷爲qxl
顯卡設備,並在/usr/lib/xorg/modules/driver中尋找該設備的應用層驅動,qxl應用層驅動名爲qxl_drv.so。

2)xorg中的分辨率設置執行流程

Created with Raphaël 2.1.2設置分辨率drmmode_xf86crtc_resize(所有庫均具有相同入口)

3)xf86-qxl中的分辨率設置執行流程

Created with Raphaël 2.1.2drmmode_xf86crtc_resizedrmModeAddFB

3) libdrm中的分辨率設置執行流程

Created with Raphaël 2.1.2drmModeAddFB->DRM_IOCTLioctl(QXL_ALLOC_SURF)

4) kernel中的分辨率設置執行流程

Created with Raphaël 2.1.2qxl_alloc_surf_ioctlqxl_gem_object_create_with_handleqxl_gem_object_createqxl_bo_createttm_bo_init

主要出錯點在ttm_bo_init中的drm_vma_offset_add,而分配size由drmmode_xf86crtc_resize決定並傳入,分配該內存主要用於應用層和內核共享的famebuffer的內存區域,用於xorg存儲圖像,內核讀取。
計算公式如下:
size = (width * cpp + 1) * height
其中cpp = (scrn->bitsPerPixel + 7) / 8
其中bpp一般爲32,由於分配該存儲空間之時前一段存儲空間尚未銷燬,實際大小粗略計算爲
1920 × 4 × 1080 = 8M
即應爲該framebuffer在內核中分配大約8M的共享空間。

而實際能分配內存的上限來自於初始化函數ttm_bo_init_mm中對顯存的設置,分配見下調用函數:
ttm_bo_init_mm(&qdev->mman.bdev, TTM_PL_VRAM, num_io_pages);
其中初始化最大值取決於num_io_pages,該值通過如下計算可得出vram_size:
vram_size = num_io_pages * PAGE_SIZE / (1024 * 1024)
值vram_size來源於qemu-system-x86_64執行中使用的的參數vram_size=8388608,該參數由ovirt固定在程序中。

在客戶機中運行:

$ lspci -v  -s 00:02.0
00:02.0 VGA compatible controller: Red Hat, Inc. QXL paravirtual graphic card (rev 04) (prog-if 00 [VGA controller])
    Subsystem: Red Hat, Inc QEMU Virtual Machine
    Flags: fast devsel, IRQ 10
    Memory at f8000000 (32-bit, non-prefetchable) [size=64M]
    Memory at fc000000 (32-bit, non-prefetchable) [size=8M]
    Memory at fc850000 (32-bit, non-prefetchable) [size=8K]
    I/O ports at c040 [size=32]
    Expansion ROM at fc840000 [disabled] [size=64K]
    Kernel driver in use: qxl
    Kernel modules: qxl

可以看到該fc000000中的vram_size是8M,而根據前面計算的new_framebuffer + old_framebuffer的大小
8M + n > vram_size,所以導致了分辨率設置失敗,因爲分配framebuffer失敗。

通過如下命令更新數據庫中:
update vmDevice SET vmDevice=”{\”specParams\”:{\”vgamem\”:\”65536\”,\”heads\”:\”1\”,\”vram\”:\”65536\”,\”ram\”:\”65536\”},\”type\”:\”video\”,\”device\”:\”qxl\”,\”deviceId\”:\”026af321-efc4-4859-9c13-5fcffd3f9c06\”}” where vmDevice=”{\”specParams\”:{\”vgamem\”:\”16384\”,\”heads\”:\”1\”,\”vram\”:\”8192\”,\”ram\”:\”65536\”},\”type\”:\”video\”,\”device\”:\”qxl\”,\”deviceId\”:\”026af321-efc4-4859-9c13-5fcffd3f9c06\”}”;

關閉、重新啓動虛擬機,執行如下:

$ lspci -v  -s 00:02.0
00:02.0 VGA compatible controller: Red Hat, Inc. QXL paravirtual graphic card (rev 04) (prog-if 00 [VGA controller])
    Subsystem: Red Hat, Inc QEMU Virtual Machine
    Flags: fast devsel, IRQ 10
    Memory at f0000000 (32-bit, non-prefetchable) [size=128M]
    Memory at f8000000 (32-bit, non-prefetchable) [size=64M]
    Memory at fc050000 (32-bit, non-prefetchable) [size=8K]
    I/O ports at c040 [size=32]
    Expansion ROM at fc040000 [disabled] [size=64K]
    Kernel driver in use: qxl
    Kernel modules: qxl

測試結果:
vram_size大小增大到64M,實測在ubuntu16.04, ubuntu18.04, Centos7中設置分辨率均正常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章