* [Qemu-devel] [PATCH 0/8] add virtio-gpu @ 2014-09-23 13:27 Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann ` (7 more replies) 0 siblings, 8 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:27 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Hi, Initial batch of virtio-gpu patches, covering 2D support. Patch to the virtio spec has been sent to virtio-dev yesterday, a formated version can be found here: https://www.kraxel.org/virtio/ What is the virtio 1.0 state btw? Specs are final, do we have qemu/kernel patches somewhere meanwhile? please review, Gerd Gerd Hoffmann (8): virtio-gpu/2d: add hardware spec include file virtio-gpu/2d: add virtio gpu core code virtio-gpu-pci: add virtio pci support virtio-vga: add virtio gpu device with vga compatibility virtio-vga: add '-vga virtio' support virtio-vga: add vgabios configuration virtio-vga: add vgabios binary virtio-gpu: add to display-vga test Makefile | 2 +- default-configs/x86_64-softmmu.mak | 3 + hw/display/Makefile.objs | 4 + hw/display/virtio-gpu-pci.c | 80 ++++ hw/display/virtio-gpu.c | 863 +++++++++++++++++++++++++++++++++++++ hw/display/virtio-vga.c | 169 ++++++++ hw/pci/pci.c | 2 + hw/virtio/virtio-pci.h | 15 + include/hw/pci/pci.h | 1 + include/hw/virtio/virtgpu_hw.h | 207 +++++++++ include/hw/virtio/virtio-gpu.h | 147 +++++++ include/sysemu/sysemu.h | 2 +- pc-bios/vgabios-virtio.bin | Bin 0 -> 37376 bytes roms/Makefile | 2 +- roms/config.vga-virtio | 6 + tests/Makefile | 3 + tests/display-vga-test.c | 18 + trace-events | 14 + vl.c | 13 + 19 files changed, 1548 insertions(+), 3 deletions(-) create mode 100644 hw/display/virtio-gpu-pci.c create mode 100644 hw/display/virtio-gpu.c create mode 100644 hw/display/virtio-vga.c create mode 100644 include/hw/virtio/virtgpu_hw.h create mode 100644 include/hw/virtio/virtio-gpu.h create mode 100644 pc-bios/vgabios-virtio.bin create mode 100644 roms/config.vga-virtio -- 1.8.3.1 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-25 15:02 ` Gerd Hoffmann 2014-10-15 10:05 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 2/8] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann ` (6 subsequent siblings) 7 siblings, 2 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel; +Cc: Dave Airlie, Gerd Hoffmann This patch adds the header file with structs and defines for the virtio based gpu device. Covers 2d operations only. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- include/hw/virtio/virtgpu_hw.h | 207 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 include/hw/virtio/virtgpu_hw.h diff --git a/include/hw/virtio/virtgpu_hw.h b/include/hw/virtio/virtgpu_hw.h new file mode 100644 index 0000000..b421a4e --- /dev/null +++ b/include/hw/virtio/virtgpu_hw.h @@ -0,0 +1,207 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This header is BSD licensed so anyone can use the definitions + * to implement compatible drivers/servers: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef VIRTIO_GPU_HW_H +#define VIRTIO_GPU_HW_H + +enum virtio_gpu_ctrl_type { + VIRTIO_GPU_UNDEFINED = 0, + + /* 2d commands */ + VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, + VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, + VIRTIO_GPU_CMD_RESOURCE_UNREF, + VIRTIO_GPU_CMD_SET_SCANOUT, + VIRTIO_GPU_CMD_RESOURCE_FLUSH, + VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, + VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, + VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, + + /* cursor commands */ + VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, + VIRTIO_GPU_CMD_MOVE_CURSOR, + + /* success responses */ + VIRTIO_GPU_RESP_OK_NODATA = 0x1100, + VIRTIO_GPU_RESP_OK_DISPLAY_INFO, + + /* error responses */ + VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, + VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, + VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID, + VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID, + VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER, +}; + +#define VIRTIO_GPU_FLAG_FENCE (1 << 0) + +struct virtio_gpu_ctrl_hdr { + uint32_t type; + uint32_t flags; + uint64_t fence_id; + uint32_t ctx_id; + uint32_t padding; +}; + +/* data passed in the cursor vq */ + +struct virtio_gpu_cursor_pos { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ +struct virtio_gpu_update_cursor { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_cursor_pos pos; /* update & move */ + uint32_t resource_id; /* update only */ + uint32_t hot_x; /* update only */ + uint32_t hot_y; /* update only */ + uint32_t padding; +}; + +/* data passed in the control vq, 2d related */ + +/* VIRTIO_GPU_CMD_RESOURCE_UNREF */ +struct virtio_gpu_resource_unref { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */ +struct virtio_gpu_resource_create_2d { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t format; + uint32_t width; + uint32_t height; +}; + +/* VIRTIO_GPU_CMD_SET_SCANOUT */ +struct virtio_gpu_set_scanout { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t scanout_id; + uint32_t resource_id; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */ +struct virtio_gpu_resource_flush { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; + uint32_t padding; +}; + +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */ +struct virtio_gpu_transfer_to_host_2d { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; +}; + +struct virtio_gpu_mem_entry { + uint64_t addr; + uint32_t length; + uint32_t pad; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */ +struct virtio_gpu_resource_attach_backing { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t nr_entries; +}; + +/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */ +struct virtio_gpu_resource_detach_backing { + struct virtio_gpu_ctrl_hdr hdr; + uint32_t resource_id; + uint32_t padding; +}; + +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ +#define VIRTIO_GPU_MAX_SCANOUTS 16 +struct virtio_gpu_resp_display_info { + struct virtio_gpu_ctrl_hdr hdr; + struct virtio_gpu_display_one { + uint32_t enabled; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; + uint32_t flags; + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; +}; + +#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) + +struct virtio_gpu_config { + uint32_t events_read; + uint32_t events_clear; + uint32_t num_scanouts; + uint32_t reserved; +}; + +/* simple formats for fbcon/X use */ +enum virtio_gpu_formats { + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, + + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, + + VIRTIO_GPU_FORMAT_R8_UNORM = 64, +}; + +#endif -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann @ 2014-09-25 15:02 ` Gerd Hoffmann 2014-09-30 0:27 ` Dave Airlie 2014-10-15 10:05 ` Gerd Hoffmann 1 sibling, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-25 15:02 UTC (permalink / raw) To: qemu-devel; +Cc: Dave Airlie Hi Dave, Triggered by the framebuffer endian issues we have with stdvga I've started to check where we stand with virtio-gpu and whenever we have to fix something in the virtio protocol before setting in stone with the upstream merge. Fixed the protocol. Basically s/uint32_t/__le32/g. No changes on x86_64 obviously. Fixed the kernel driver to byteswap values when needed. See https://www.kraxel.org/cgit/linux/log/?h=virtio-gpu-rebase Result is bigendian guest on little endian host boots fine (without virgl). Colors are wrong though. Other way around still needs a bunch of fixes in qemu so virtio-gpu works correctly on bigendian hosts. To be done. So, on the color issue: How are these defined exactly? > + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, > + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, > + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, > + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, Looking at the code it seems the name defines the byte ordering in memory, i.e. "B8G8R8A8" means blue first, then red, then green, then alpha. Or DRM_FORMAT_ARGB8888 on little endian / DRM_FORMAT_BGRX8888 on big endian. Correct? Easy fix in the guest driver then ... > + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, > + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, Do we really wanna go down this route? I'm inclined to just zap 16bpp support. > + VIRTIO_GPU_FORMAT_R8_UNORM = 64, What is this btw? Looks like gray or alpha, but why "R8" not "G8" or "A8" then? Why the gap in the enumeration? With the formats being clarified fixed we are settled for 2d mode I think. What about 3d mode? We are passing blobs between virglrenderer and guest driver: capabilities and gallium 3d command stream. What happens to them in case host and guest endianness don't match? I think at least the capabilities have 32bit values which need to be swapped. Dunno about the gallium commands ... cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-25 15:02 ` Gerd Hoffmann @ 2014-09-30 0:27 ` Dave Airlie 2014-09-30 7:54 ` Gerd Hoffmann 2014-09-30 7:55 ` Gerd Hoffmann 0 siblings, 2 replies; 19+ messages in thread From: Dave Airlie @ 2014-09-30 0:27 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: Dave Airlie, qemu-devel@nongnu.org > Triggered by the framebuffer endian issues we have with stdvga I've > started to check where we stand with virtio-gpu and whenever we have to > fix something in the virtio protocol before setting in stone with the > upstream merge. Let me start by saying its not that I don't care about endianness, but its a mess I had hoped to avoid until someone else care more about it. We haven't even managed to get endianness fixed for real 3D gpu hardware yet, We sort of have decent endianness support for the llvmpipe sw driver now, after I spent a week trawling patches and fixing up the results. So before we try fixing things, we probably need to design something that defines where all the swapping happens, and what formats the virgl "hw" device supports. The main problem is getting an efficient solution that avoids double swapping of the major items like texture and vertex data if we can in some scenarios. Currently the virgl "hw" supports little endian defined formats, as per the gallium interface, i.e. B8G8R8A8 means blue/red/green/alpha, http://gallium.readthedocs.org/en/latest/format.html is the documentation. > >> + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, >> + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, > > Do we really wanna go down this route? I'm inclined to just zap 16bpp > support. We have to support 16bpp as an OpenGL format no matter what, and this is why endianness sucks, we have lots of strange ass formats we need to send over the wire, that have no nicely defined endianness, like Z24S8. > >> + VIRTIO_GPU_FORMAT_R8_UNORM = 64, > > What is this btw? Looks like gray or alpha, but why "R8" not "G8" or > "A8" then? Why the gap in the enumeration? Red 8, the enumeration is taken from the gallium formats list, rather than reinventing our own. Most modern GPU hardware doesn't really have A8 texture support, as it was deprecated in newer OpenGL. > > What about 3d mode? We are passing blobs between virglrenderer and > guest driver: capabilities and gallium 3d command stream. What happens > to them in case host and guest endianness don't match? I think at least > the capabilities have 32bit values which need to be swapped. Dunno > about the gallium commands ... For 3D we probably need to define the gallium command streams to be little endian, however the big problem is the data that is stored inside objects. Texture and vertex, constants, indices etc. How do we decide to swap these, when do we swap things, on the DMA transfers to the host, do we just swap the formats on the host side etc. I probably need to spend some time working this out with BenH, but I'm not really sure how we can avoid backing ourselves into a large inefficent hole at some point. Dave. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-30 0:27 ` Dave Airlie @ 2014-09-30 7:54 ` Gerd Hoffmann 2014-09-30 7:55 ` Gerd Hoffmann 1 sibling, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-30 7:54 UTC (permalink / raw) To: Dave Airlie; +Cc: Dave Airlie, qemu-devel@nongnu.org On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote: > > Triggered by the framebuffer endian issues we have with stdvga I've > > started to check where we stand with virtio-gpu and whenever we have to > > fix something in the virtio protocol before setting in stone with the > > upstream merge. > > Let me start by saying its not that I don't care about endianness, but > its a mess I had hoped to avoid until someone else care more about it. Understood. It's a big mess indeed. > So before we try fixing things, we probably need to design something > that defines > where all the swapping happens, and what formats the virgl "hw" device supports. 2D case is easy. Everything is little endian. kernel driver / qemu are doing the byteswaps for the structs sent over the control pipe. Problem with 3D is that both qemu and kernel driver passing through data where they don't even know what is inside, so they can't do the byteswapping. > The main problem is getting an efficient solution that avoids double swapping > of the major items like texture and vertex data if we can in some scenarios. Yes. > > Currently the virgl "hw" supports little endian defined formats, as > per the gallium > interface, i.e. B8G8R8A8 means blue/red/green/alpha, > > http://gallium.readthedocs.org/en/latest/format.html > is the documentation. Thanks. > >> + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, > >> + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, > > > > Do we really wanna go down this route? I'm inclined to just zap 16bpp > > support. > > We have to support 16bpp as an OpenGL format no matter what, and this > is why endianness sucks, we have lots of strange ass formats we need > to send over the wire, that have no nicely defined endianness, like Z24S8. Ok. But for 2D we can just not support it, right? > > What about 3d mode? We are passing blobs between virglrenderer and > > guest driver: capabilities and gallium 3d command stream. What happens > > to them in case host and guest endianness don't match? I think at least > > the capabilities have 32bit values which need to be swapped. Dunno > > about the gallium commands ... > > For 3D we probably need to define the gallium command streams to be > little endian, however the big problem is the data that is stored > inside objects. > Texture and vertex, constants, indices etc. How do we decide to swap these, > when do we swap things, on the DMA transfers to the host, do we just > swap the formats on the host side etc. > > I probably need to spend some time working this out with BenH, but > I'm not really sure how we can avoid backing ourselves into a large inefficent > hole at some point. I surely don't wanna go down that route, and I think it is reasonable to just not support 3D/virgl mode if we would have to swap data. So, we could define *two* virgl feature bits. One for little endian, one for bigendian. endianness applies to the gallium command stream and to gallium formats using integers in host endianess. On the host side we'll go set the feature bit matching host endianness. qemu handles the virtqueue command struct swapping, and virglrenderer should only see native endian. On the guest side we'll look for the feature bit matching guest endianness, and if it isn't set due to guest + host having different byte order you'll get 2D support only. The endianness negotiation is a bit iffy, but that way it is possible to have virgl on bigendian without swapping everything twice. The other reasonable way would be to simply define virgl being little endian. Bigendian guests / hosts would either simply not support 3D then, or implement swapping. But in the bigendian-guest on bigendian-host case we'll swap everything twice then ... cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-30 0:27 ` Dave Airlie 2014-09-30 7:54 ` Gerd Hoffmann @ 2014-09-30 7:55 ` Gerd Hoffmann 2014-10-03 4:38 ` Dave Airlie 1 sibling, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-30 7:55 UTC (permalink / raw) To: Dave Airlie; +Cc: Dave Airlie, qemu-devel@nongnu.org On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote: > > Triggered by the framebuffer endian issues we have with stdvga I've > > started to check where we stand with virtio-gpu and whenever we have to > > fix something in the virtio protocol before setting in stone with the > > upstream merge. > > Let me start by saying its not that I don't care about endianness, but > its a mess I had hoped to avoid until someone else care more about it. Understood. It's a big mess indeed. > So before we try fixing things, we probably need to design something > that defines > where all the swapping happens, and what formats the virgl "hw" device supports. 2D case is easy. Everything is little endian. kernel driver / qemu are doing the byteswaps for the structs sent over the control pipe. Problem with 3D is that both qemu and kernel driver passing through data where they don't even know what is inside, so they can't do the byteswapping. > The main problem is getting an efficient solution that avoids double swapping > of the major items like texture and vertex data if we can in some scenarios. Yes. > > Currently the virgl "hw" supports little endian defined formats, as > per the gallium > interface, i.e. B8G8R8A8 means blue/red/green/alpha, > > http://gallium.readthedocs.org/en/latest/format.html > is the documentation. Thanks. > >> + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, > >> + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, > > > > Do we really wanna go down this route? I'm inclined to just zap 16bpp > > support. > > We have to support 16bpp as an OpenGL format no matter what, and this > is why endianness sucks, we have lots of strange ass formats we need > to send over the wire, that have no nicely defined endianness, like Z24S8. Ok. But for 2D we can just not support it, right? > > What about 3d mode? We are passing blobs between virglrenderer and > > guest driver: capabilities and gallium 3d command stream. What happens > > to them in case host and guest endianness don't match? I think at least > > the capabilities have 32bit values which need to be swapped. Dunno > > about the gallium commands ... > > For 3D we probably need to define the gallium command streams to be > little endian, however the big problem is the data that is stored > inside objects. > Texture and vertex, constants, indices etc. How do we decide to swap these, > when do we swap things, on the DMA transfers to the host, do we just > swap the formats on the host side etc. > > I probably need to spend some time working this out with BenH, but > I'm not really sure how we can avoid backing ourselves into a large inefficent > hole at some point. I surely don't wanna go down that route, and I think it is reasonable to just not support 3D/virgl mode if we would have to swap data. So, we could define *two* virgl feature bits. One for little endian, one for bigendian. endianness applies to the gallium command stream and to gallium formats using integers in host endianess. On the host side we'll go set the feature bit matching host endianness. qemu handles the virtqueue command struct swapping, and virglrenderer should only see native endian. On the guest side we'll look for the feature bit matching guest endianness, and if it isn't set due to guest + host having different byte order you'll get 2D support only. The endianness negotiation is a bit iffy, but that way it is possible to have virgl on bigendian without swapping everything twice. The other reasonable way would be to simply define virgl being little endian. Bigendian guests / hosts would either simply not support 3D then, or implement swapping. But in the bigendian-guest on bigendian-host case we'll swap everything twice then ... cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-30 7:55 ` Gerd Hoffmann @ 2014-10-03 4:38 ` Dave Airlie 2014-10-06 9:20 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Dave Airlie @ 2014-10-03 4:38 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: Dave Airlie, qemu-devel@nongnu.org On 30 September 2014 17:55, Gerd Hoffmann <kraxel@redhat.com> wrote: > > On Di, 2014-09-30 at 10:27 +1000, Dave Airlie wrote: >> > Triggered by the framebuffer endian issues we have with stdvga I've >> > started to check where we stand with virtio-gpu and whenever we have to >> > fix something in the virtio protocol before setting in stone with the >> > upstream merge. >> >> Let me start by saying its not that I don't care about endianness, but >> its a mess I had hoped to avoid until someone else care more about it. > > Understood. It's a big mess indeed. > >> So before we try fixing things, we probably need to design something >> that defines >> where all the swapping happens, and what formats the virgl "hw" device supports. > > 2D case is easy. Everything is little endian. kernel driver / qemu are > doing the byteswaps for the structs sent over the control pipe. > > Problem with 3D is that both qemu and kernel driver passing through data > where they don't even know what is inside, so they can't do the > byteswapping. > >> The main problem is getting an efficient solution that avoids double swapping >> of the major items like texture and vertex data if we can in some scenarios. > > Yes. > >> >> Currently the virgl "hw" supports little endian defined formats, as >> per the gallium >> interface, i.e. B8G8R8A8 means blue/red/green/alpha, >> >> http://gallium.readthedocs.org/en/latest/format.html >> is the documentation. > > Thanks. > >> >> + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, >> >> + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, >> > >> > Do we really wanna go down this route? I'm inclined to just zap 16bpp >> > support. >> >> We have to support 16bpp as an OpenGL format no matter what, and this >> is why endianness sucks, we have lots of strange ass formats we need >> to send over the wire, that have no nicely defined endianness, like Z24S8. > > Ok. But for 2D we can just not support it, right? We can, I expect some pushback at some point, people still want to test with 16bpp for other areas, and it would be nice to know they can. But I don't really care about it personally. I just though we should provide at least a basic number of working bpps (8,16,32). >> > What about 3d mode? We are passing blobs between virglrenderer and >> > guest driver: capabilities and gallium 3d command stream. What happens >> > to them in case host and guest endianness don't match? I think at least >> > the capabilities have 32bit values which need to be swapped. Dunno >> > about the gallium commands ... >> >> For 3D we probably need to define the gallium command streams to be >> little endian, however the big problem is the data that is stored >> inside objects. >> Texture and vertex, constants, indices etc. How do we decide to swap these, >> when do we swap things, on the DMA transfers to the host, do we just >> swap the formats on the host side etc. >> >> I probably need to spend some time working this out with BenH, but >> I'm not really sure how we can avoid backing ourselves into a large inefficent >> hole at some point. > > I surely don't wanna go down that route, and I think it is reasonable to > just not support 3D/virgl mode if we would have to swap data. I think initially not support 3D mode is the way to go until we can work it out. > > > So, we could define *two* virgl feature bits. One for little endian, > one for bigendian. endianness applies to the gallium command stream and > to gallium formats using integers in host endianess. > > On the host side we'll go set the feature bit matching host endianness. > qemu handles the virtqueue command struct swapping, and virglrenderer > should only see native endian. > > On the guest side we'll look for the feature bit matching guest > endianness, and if it isn't set due to guest + host having different > byte order you'll get 2D support only. > > The endianness negotiation is a bit iffy, but that way it is possible to > have virgl on bigendian without swapping everything twice. > > > The other reasonable way would be to simply define virgl being little > endian. Bigendian guests / hosts would either simply not support 3D > then, or implement swapping. But in the bigendian-guest on > bigendian-host case we'll swap everything twice then ... > I think we should probably move a few more formats from the 3D side into the 2D side, so we can have the guests just pick the LE format it requires http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354 is what gallium currently does, and we could just provide XRGB, XBGR formats in both endianness and have the guest pick the one it wants to use. The 2D pixman code would need updating to provide 2D support for these formats as well. I suspect I could add an endian cap for the 3D bits that I could pass through from guest to host. How do you test guests with big endian? Isn't it really slow? Dave. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-10-03 4:38 ` Dave Airlie @ 2014-10-06 9:20 ` Gerd Hoffmann 2014-10-16 3:53 ` Dave Airlie 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2014-10-06 9:20 UTC (permalink / raw) To: Dave Airlie; +Cc: Dave Airlie, qemu-devel@nongnu.org Hi, > >> >> + VIRTIO_GPU_FORMAT_B5G5R5A1_UNORM = 5, > >> >> + VIRTIO_GPU_FORMAT_B5G6R5_UNORM = 7, > >> > > > Ok. But for 2D we can just not support it, right? > > We can, I expect some pushback at some point, people still want to > test with 16bpp for other areas, and it would be nice to know they > can. But I don't really care about it personally. I just though we > should provide at least a basic number of working bpps (8,16,32). Lets try to get away with 32bpp only in 2d mode then. bochsdrm likewise supports 32bpp only and I yet have to see a request for 16bpp or even 8bpp support. > I think we should probably move a few more formats from the 3D side > into the 2D side, so we can have the guests just pick the LE format > it requires > > http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354 > > is what gallium currently does, and we could just provide XRGB, XBGR > formats in both endianness > and have the guest pick the one it wants to use. PIPE_FORMAT_R8G8B8A8_UNORM = 67, PIPE_FORMAT_X8B8G8R8_UNORM = 68, PIPE_FORMAT_A8B8G8R8_UNORM = 121, PIPE_FORMAT_R8G8B8X8_UNORM = 134, With the last two ones being in a /* TODO: re-order these */ block. How stable are these numbers? > The 2D pixman code would need updating to provide 2D support for these > formats as well. Yep. Mapping the 32bpp formats to pixmap formats is easy. > I suspect I could add an endian cap for the 3D bits that I could pass > through from guest to host. I was thinking about using virtio feature bit. Advantage is that the guest will tell the host which features it'll use. Initially this doesn't matter much as the host will support only one endianness anyway. But in case we get the byteswapping work reasonable well some day and the host supports both be and le virgl we'll know that way which endianness the guest is using. > How do you test guests with big endian? Isn't it really slow? emulated pseries machine with fedora ppc64. Yes, it is slow. Building a kernel with virtio-gpu driver takes a day or so. cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-10-06 9:20 ` Gerd Hoffmann @ 2014-10-16 3:53 ` Dave Airlie 2014-10-16 12:18 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Dave Airlie @ 2014-10-16 3:53 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: Dave Airlie, qemu-devel@nongnu.org > > Lets try to get away with 32bpp only in 2d mode then. > > bochsdrm likewise supports 32bpp only and I yet have to see a request > for 16bpp or even 8bpp support. > >> I think we should probably move a few more formats from the 3D side >> into the 2D side, so we can have the guests just pick the LE format >> it requires >> >> http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/include/pipe/p_format.h#n354 >> >> is what gallium currently does, and we could just provide XRGB, XBGR >> formats in both endianness >> and have the guest pick the one it wants to use. > > PIPE_FORMAT_R8G8B8A8_UNORM = 67, > PIPE_FORMAT_X8B8G8R8_UNORM = 68, > > PIPE_FORMAT_A8B8G8R8_UNORM = 121, > PIPE_FORMAT_R8G8B8X8_UNORM = 134, > > With the last two ones being in a /* TODO: re-order these */ block. > How stable are these numbers? In theory the mesa/gallium numbers aren't stable, though I've never seen them change yet, If they diverge in the future I'll just provide a remapping table inside the guest driver. So it should be fine to expose these formats for 2D use. > Initially this doesn't matter much as the host will support only one > endianness anyway. > > But in case we get the byteswapping work reasonable well some day and > the host supports both be and le virgl we'll know that way which > endianness the guest is using. > >> How do you test guests with big endian? Isn't it really slow? > > emulated pseries machine with fedora ppc64. Yes, it is slow. Building > a kernel with virtio-gpu driver takes a day or so. I spent a little while trying to get a ppc64 f20 install to complete, just using the F20 qemu ppc64 system package but hit a bug I think is related to missing SIMD instructions, so I'm not sure how best to move forward with getting a test platform here. Dave. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-10-16 3:53 ` Dave Airlie @ 2014-10-16 12:18 ` Gerd Hoffmann 0 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-10-16 12:18 UTC (permalink / raw) To: Dave Airlie; +Cc: Dave Airlie, qemu-devel@nongnu.org Hi, > > How stable are these numbers? > > In theory the mesa/gallium numbers aren't stable, though I've never > seen them change yet, > > If they diverge in the future I'll just provide a remapping table > inside the guest driver. > > So it should be fine to expose these formats for 2D use. Good. > >> How do you test guests with big endian? Isn't it really slow? > > > > emulated pseries machine with fedora ppc64. Yes, it is slow. Building > > a kernel with virtio-gpu driver takes a day or so. > > I spent a little while trying to get a ppc64 f20 install to complete, just > using the F20 qemu ppc64 system package but hit a bug I > think is related to missing SIMD instructions, so I'm not sure how best > to move forward with getting a test platform here. I'm using self-compiled qemu 2.1 which works fine, so it looks like this issue has been fixed meanwhile. If you want something newer without manually building it you can try the virt-preview repo (see https://fedoraproject.org/wiki/Virtualization_Preview_Repository). cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann 2014-09-25 15:02 ` Gerd Hoffmann @ 2014-10-15 10:05 ` Gerd Hoffmann 2014-10-16 3:55 ` Dave Airlie 1 sibling, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2014-10-15 10:05 UTC (permalink / raw) To: qemu-devel; +Cc: Dave Airlie Hi, > +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ > +#define VIRTIO_GPU_MAX_SCANOUTS 16 > +struct virtio_gpu_resp_display_info { > + struct virtio_gpu_ctrl_hdr hdr; > + struct virtio_gpu_display_one { > + uint32_t enabled; > + uint32_t width; > + uint32_t height; > + uint32_t x; > + uint32_t y; > + uint32_t flags; > + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; One more thing: I think it would be a good idea to add the display resolution here. We start seeing highres displays on desktops, and the guest should know whenever the host display runs at 100 or 300 dpi ... What do you think? cheers, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file 2014-10-15 10:05 ` Gerd Hoffmann @ 2014-10-16 3:55 ` Dave Airlie 0 siblings, 0 replies; 19+ messages in thread From: Dave Airlie @ 2014-10-16 3:55 UTC (permalink / raw) To: Gerd Hoffmann; +Cc: Dave Airlie, qemu-devel@nongnu.org On 15 October 2014 20:05, Gerd Hoffmann <kraxel@redhat.com> wrote: > Hi, > >> +/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */ >> +#define VIRTIO_GPU_MAX_SCANOUTS 16 >> +struct virtio_gpu_resp_display_info { >> + struct virtio_gpu_ctrl_hdr hdr; >> + struct virtio_gpu_display_one { >> + uint32_t enabled; >> + uint32_t width; >> + uint32_t height; >> + uint32_t x; >> + uint32_t y; >> + uint32_t flags; >> + } pmodes[VIRTIO_GPU_MAX_SCANOUTS]; > > One more thing: I think it would be a good idea to add the display > resolution here. We start seeing highres displays on desktops, and the > guest should know whenever the host display runs at 100 or 300 dpi ... > > What do you think? Passing host display side into the guest isn't going to help, unless you are running in full screen, I suppose the guest could adjust the numbers, but what happens with viewers, if I connect on a hidpi and move to a lodpi screen. I think this would require a lot more thought in how it would work in some use-cases. That said reserving 2 32 bit fields for possible screen measurements might future proof things a little, though most OSes use EDID to detect this sort of thing, so we might not find a great use for it later. Dave. ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 2/8] virtio-gpu/2d: add virtio gpu core code 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 3/8] virtio-gpu-pci: add virtio pci support Gerd Hoffmann ` (5 subsequent siblings) 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin This patch adds the core code for virtio gpu emulation, covering 2d support. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- default-configs/x86_64-softmmu.mak | 1 + hw/display/Makefile.objs | 2 + hw/display/virtio-gpu.c | 863 +++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-gpu.h | 147 +++++++ trace-events | 14 + 5 files changed, 1027 insertions(+) create mode 100644 hw/display/virtio-gpu.c create mode 100644 include/hw/virtio/virtio-gpu.h diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 66557ac..75a123a 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -9,6 +9,7 @@ CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y +CONFIG_VIRTIO_GPU=y CONFIG_VMMOUSE=y CONFIG_SERIAL=y CONFIG_PARALLEL=y diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 7ed76a9..29f179f 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -33,3 +33,5 @@ obj-$(CONFIG_CG3) += cg3.o obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o + +obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c new file mode 100644 index 0000000..2f1cbd4 --- /dev/null +++ b/hw/display/virtio-gpu.c @@ -0,0 +1,863 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" +#include "qemu/iov.h" +#include "ui/console.h" +#include "trace.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-bus.h" + +static struct virtio_gpu_simple_resource* +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); + +static void update_cursor_data_simple(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) +{ + struct virtio_gpu_simple_resource *res; + uint32_t pixels; + + res = virtio_gpu_find_resource(g, resource_id); + if (!res) { + return; + } + + pixels = s->current_cursor->width * s->current_cursor->height; + memcpy(s->current_cursor->data, + pixman_image_get_data(res->image), + pixels * sizeof(uint32_t)); +} + +static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) +{ + struct virtio_gpu_scanout *s; + + if (cursor->pos.scanout_id >= g->conf.max_outputs) { + return; + } + s = &g->scanout[cursor->pos.scanout_id]; + + if (cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR) { + if (!s->current_cursor) { + s->current_cursor = cursor_alloc(64, 64); + } + + s->current_cursor->hot_x = cursor->hot_x; + s->current_cursor->hot_y = cursor->hot_y; + + if (cursor->resource_id > 0) { + update_cursor_data_simple(g, s, cursor->resource_id); + } + dpy_cursor_define(s->con, s->current_cursor); + } + dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y, + cursor->resource_id ? 1 : 0); +} + +static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + memcpy(config, &g->virtio_config, sizeof(g->virtio_config)); +} + +static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + struct virtio_gpu_config vgconfig; + + memcpy(&vgconfig, config, sizeof(g->virtio_config)); + + if (vgconfig.events_clear) { + g->virtio_config.events_read &= ~vgconfig.events_clear; + } +} + +static uint32_t virtio_gpu_get_features(VirtIODevice *vdev, uint32_t features) +{ + return features; +} + +static void virtio_gpu_set_features(VirtIODevice *vdev, uint32_t features) +{ +} + +static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type) +{ + g->virtio_config.events_read |= event_type; + virtio_notify_config(&g->parent_obj); +} + +static struct virtio_gpu_simple_resource * +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) +{ + struct virtio_gpu_simple_resource *res; + + QTAILQ_FOREACH(res, &g->reslist, next) { + if (res->resource_id == resource_id) { + return res; + } + } + return NULL; +} + +void virtio_gpu_ctrl_response(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + struct virtio_gpu_ctrl_hdr *resp, + size_t resp_len) +{ + size_t s; + + if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) { + resp->flags |= VIRTIO_GPU_FLAG_FENCE; + resp->fence_id = cmd->cmd_hdr.fence_id; + resp->ctx_id = cmd->cmd_hdr.ctx_id; + } + s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len); + if (s != resp_len) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: response size incorrect %zu vs %zu\n", + __func__, s, resp_len); + } + virtqueue_push(cmd->vq, &cmd->elem, s); + virtio_notify(VIRTIO_DEVICE(g), cmd->vq); + cmd->finished = true; +} + +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + enum virtio_gpu_ctrl_type type) +{ + struct virtio_gpu_ctrl_hdr resp; + + memset(&resp, 0, sizeof(resp)); + resp.type = type; + virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp)); +} + +static void +virtio_gpu_fill_display_info(VirtIOGPU *g, + struct virtio_gpu_resp_display_info *dpy_info) +{ + int i; + + for (i = 0; i < g->conf.max_outputs; i++) { + if (g->enabled_output_bitmask & (1 << i)) { + dpy_info->pmodes[i].enabled = 1; + dpy_info->pmodes[i].width = g->req_state[i].width; + dpy_info->pmodes[i].height = g->req_state[i].height; + } + } +} + +void virtio_gpu_get_display_info(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resp_display_info display_info; + + trace_virtio_gpu_cmd_get_display_info(); + memset(&display_info, 0, sizeof(display_info)); + display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO; + virtio_gpu_fill_display_info(g, &display_info); + virtio_gpu_ctrl_response(g, cmd, &display_info.hdr, + sizeof(display_info)); +} + +static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format) +{ + switch (virtio_gpu_format) { + case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: + return PIXMAN_x8r8g8b8; + case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: + return PIXMAN_a8r8g8b8; + case VIRTIO_GPU_FORMAT_B5G6R5_UNORM: + return PIXMAN_r5g6b5; + default: + break; + } + return 0; +} + +static void virtio_gpu_resource_create_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + pixman_format_code_t pformat; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_create_2d c2d; + + VIRTIO_GPU_FILL_CMD(c2d); + trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, + c2d.width, c2d.height); + + res = virtio_gpu_find_resource(g, c2d.resource_id); + if (res) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n", + __func__, c2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + res = g_new0(struct virtio_gpu_simple_resource, 1); + + res->width = c2d.width; + res->height = c2d.height; + res->format = c2d.format; + res->resource_id = c2d.resource_id; + + pformat = get_pixman_format(c2d.format); + if (!pformat) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: host couldn't handle guest format %d\n", + __func__, c2d.format); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + res->image = pixman_image_create_bits(pformat, + c2d.width, + c2d.height, + NULL, 0); + + if (!res->image) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: resource creation failed %d %d %d\n", + __func__, c2d.resource_id, c2d.width, c2d.height); + g_free(res); + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); +} + +static void virtio_gpu_resource_destroy(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res) +{ + pixman_image_unref(res->image); + QTAILQ_REMOVE(&g->reslist, res, next); + g_free(res); +} + +static void virtio_gpu_resource_unref(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_unref unref; + + VIRTIO_GPU_FILL_CMD(unref); + trace_virtio_gpu_cmd_res_unref(unref.resource_id); + + res = virtio_gpu_find_resource(g, unref.resource_id); + if (!res) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, unref.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + virtio_gpu_resource_destroy(g, res); +} + +static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + int h; + uint32_t src_offset, dst_offset, stride; + int bpp; + pixman_format_code_t format; + struct virtio_gpu_transfer_to_host_2d t2d; + + VIRTIO_GPU_FILL_CMD(t2d); + trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); + + res = virtio_gpu_find_resource(g, t2d.resource_id); + if (!res || !res->iov) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, t2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (t2d.x > res->width || + t2d.y > res->height || + t2d.width > res->width || + t2d.height > res->height || + t2d.x + t2d.width > res->width || + t2d.y + t2d.height > res->height) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource" + " bounds for resource %d: %d %d %d %d vs %d %d\n", + __func__, t2d.resource_id, t2d.x, t2d.y, + t2d.width, t2d.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + format = pixman_image_get_format(res->image); + bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8; + stride = pixman_image_get_stride(res->image); + + if (t2d.offset || t2d.x || t2d.y || + t2d.width != pixman_image_get_width(res->image)) { + void *img_data = pixman_image_get_data(res->image); + for (h = 0; h < t2d.height; h++) { + src_offset = t2d.offset + stride * h; + dst_offset = (t2d.y + h) * stride + (t2d.x * bpp); + + iov_to_buf(res->iov, res->iov_cnt, src_offset, + (uint8_t *)img_data + + dst_offset, t2d.width * bpp); + } + } else { + iov_to_buf(res->iov, res->iov_cnt, 0, + pixman_image_get_data(res->image), + pixman_image_get_stride(res->image) + * pixman_image_get_height(res->image)); + } +} + +static void virtio_gpu_resource_flush(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_flush rf; + pixman_region16_t flush_region; + int i; + + VIRTIO_GPU_FILL_CMD(rf); + trace_virtio_gpu_cmd_res_flush(rf.resource_id, + rf.width, rf.height, rf.x, rf.y); + + res = virtio_gpu_find_resource(g, rf.resource_id); + if (!res) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, rf.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (rf.x > res->width || + rf.y > res->height || + rf.width > res->width || + rf.height > res->height || + rf.x + rf.width > res->width || + rf.y + rf.height > res->height) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource" + " bounds for resource %d: %d %d %d %d vs %d %d\n", + __func__, rf.resource_id, rf.x, rf.y, + rf.width, rf.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + pixman_region_init_rect(&flush_region, + rf.x, rf.y, rf.width, rf.height); + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) { + struct virtio_gpu_scanout *scanout; + pixman_region16_t region, finalregion; + pixman_box16_t *extents; + + if (!(res->scanout_bitmask & (1 << i))) { + continue; + } + scanout = &g->scanout[i]; + + pixman_region_init(&finalregion); + pixman_region_init_rect(®ion, scanout->x, scanout->y, + scanout->width, scanout->height); + + pixman_region_intersect(&finalregion, &flush_region, ®ion); + pixman_region_translate(&finalregion, -scanout->x, -scanout->y); + extents = pixman_region_extents(&finalregion); + /* work out the area we need to update for each console */ + dpy_gfx_update(g->scanout[i].con, + extents->x1, extents->y1, + extents->x2 - extents->x1, + extents->y2 - extents->y1); + + pixman_region_fini(®ion); + pixman_region_fini(&finalregion); + } + pixman_region_fini(&flush_region); +} + +static void virtio_gpu_set_scanout(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_scanout *scanout; + pixman_format_code_t format; + uint32_t offset; + int bpp; + struct virtio_gpu_set_scanout ss; + + VIRTIO_GPU_FILL_CMD(ss); + trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, + ss.width, ss.height, ss.x, ss.y); + + res = virtio_gpu_find_resource(g, ss.resource_id); + g->enable = 1; + if (ss.resource_id == 0) { + scanout = &g->scanout[ss.scanout_id]; + if (g->scanout[ss.scanout_id].resource_id) { + res = virtio_gpu_find_resource(g, scanout->resource_id); + if (res) { + res->scanout_bitmask &= ~(1 << ss.scanout_id); + } + } + if (ss.scanout_id == 0 || + ss.scanout_id >= g->conf.max_outputs) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); + scanout->ds = NULL; + scanout->width = 0; + scanout->height = 0; + return; + } + + /* create a surface for this scanout */ + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT || + ss.scanout_id >= g->conf.max_outputs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + if (!res) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (ss.x > res->width || + ss.y > res->height || + ss.width > res->width || + ss.height > res->height || + ss.x + ss.width > res->width || + ss.y + ss.height > res->height) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" + " resource %d, (%d,%d)+%d,%d vs %d %d\n", + __func__, ss.scanout_id, ss.resource_id, ss.x, ss.y, + ss.width, ss.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + scanout = &g->scanout[ss.scanout_id]; + + format = pixman_image_get_format(res->image); + bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8; + offset = (ss.x * bpp) + ss.y * pixman_image_get_stride(res->image); + if (!scanout->ds || surface_data(scanout->ds) + != ((uint8_t *)pixman_image_get_data(res->image) + offset) || + scanout->width != ss.width || + scanout->height != ss.height) { + /* realloc the surface ptr */ + scanout->ds = qemu_create_displaysurface_from + (ss.width, ss.height, format, pixman_image_get_stride(res->image), + (uint8_t *)pixman_image_get_data(res->image) + offset); + if (!scanout->ds) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds); + } + + res->scanout_bitmask |= (1 << ss.scanout_id); + scanout->resource_id = ss.resource_id; + scanout->x = ss.x; + scanout->y = ss.y; + scanout->width = ss.width; + scanout->height = ss.height; +} + +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, + struct virtio_gpu_ctrl_command *cmd, + struct iovec **iov) +{ + struct virtio_gpu_mem_entry *ents; + size_t esize, s; + int i; + + esize = sizeof(*ents) * ab->nr_entries; + ents = g_malloc(esize); + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(*ab), ents, esize); + if (s != esize) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: command data size incorrect %zu vs %zu\n", + __func__, s, esize); + g_free(ents); + return -1; + } + + *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); + for (i = 0; i < ab->nr_entries; i++) { + hwaddr len = ents[i].length; + (*iov)[i].iov_len = ents[i].length; + (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1); + if (!(*iov)[i].iov_base || len != ents[i].length) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" + " resource %d element %d\n", + __func__, ab->resource_id, i); + virtio_gpu_cleanup_mapping_iov(*iov, i); + g_free(ents); + g_free(*iov); + *iov = NULL; + return -1; + } + } + g_free(ents); + return 0; +} + +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count) +{ + int i; + + for (i = 0; i < count; i++) { + cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1, + iov[i].iov_len); + } +} + +static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res) +{ + virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt); + g_free(res->iov); + res->iov = NULL; + res->iov_cnt = 0; +} + +static void +virtio_gpu_resource_attach_backing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_attach_backing ab; + int ret; + + VIRTIO_GPU_FILL_CMD(ab); + trace_virtio_gpu_cmd_res_back_attach(ab.resource_id); + + res = virtio_gpu_find_resource(g, ab.resource_id); + if (!res) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, ab.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov); + if (ret != 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + res->iov_cnt = ab.nr_entries; +} + +static void +virtio_gpu_resource_detach_backing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_detach_backing detach; + + VIRTIO_GPU_FILL_CMD(detach); + trace_virtio_gpu_cmd_res_back_detach(detach.resource_id); + + res = virtio_gpu_find_resource(g, detach.resource_id); + if (!res || !res->iov) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", + __func__, detach.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + virtio_gpu_cleanup_mapping(res); +} + +static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); + + switch (cmd->cmd_hdr.type) { + case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: + virtio_gpu_get_display_info(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: + virtio_gpu_resource_create_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNREF: + virtio_gpu_resource_unref(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + virtio_gpu_resource_flush(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: + virtio_gpu_transfer_to_host_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_SET_SCANOUT: + virtio_gpu_set_scanout(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: + virtio_gpu_resource_attach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: + virtio_gpu_resource_detach_backing(g, cmd); + break; + default: + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + break; + } + if (!cmd->finished) { + virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error : + VIRTIO_GPU_RESP_OK_NODATA); + } +} + +static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + qemu_bh_schedule(g->ctrl_bh); +} + +static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + qemu_bh_schedule(g->cursor_bh); +} + +static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + struct virtio_gpu_ctrl_command *cmd; + + if (!virtio_queue_ready(vq)) { + return; + } + + cmd = g_new(struct virtio_gpu_ctrl_command, 1); + while (virtqueue_pop(vq, &cmd->elem)) { + cmd->vq = vq; + cmd->error = 0; + cmd->finished = false; + g->stats.requests++; + + virtio_gpu_simple_process_cmd(g, cmd); + if (!cmd->finished) { + QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next); + g->stats.inflight++; + if (g->stats.max_inflight < g->stats.inflight) { + g->stats.max_inflight = g->stats.inflight; + } + fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight); + cmd = g_new(struct virtio_gpu_ctrl_command, 1); + } + } + g_free(cmd); +} + +static void virtio_gpu_ctrl_bh(void *opaque) +{ + VirtIOGPU *g = opaque; + virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq); +} + +static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + VirtQueueElement elem; + size_t s; + struct virtio_gpu_update_cursor cursor_info; + + if (!virtio_queue_ready(vq)) { + return; + } + while (virtqueue_pop(vq, &elem)) { + s = iov_to_buf(elem.out_sg, elem.out_num, 0, + &cursor_info, sizeof(cursor_info)); + if (s != sizeof(cursor_info)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: cursor size incorrect %zu vs %zu\n", + __func__, s, sizeof(cursor_info)); + } else { + update_cursor(g, &cursor_info); + } + virtqueue_push(vq, &elem, 0); + virtio_notify(vdev, vq); + } +} + +static void virtio_gpu_cursor_bh(void *opaque) +{ + VirtIOGPU *g = opaque; + virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq); +} + +static void virtio_gpu_invalidate_display(void *opaque) +{ +} + +static void virtio_gpu_update_display(void *opaque) +{ +} + +static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) +{ +} + +static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +{ + VirtIOGPU *g = opaque; + + if (idx > g->conf.max_outputs) { + return -1; + } + + g->req_state[idx].x = info->xoff; + g->req_state[idx].y = info->yoff; + g->req_state[idx].width = info->width; + g->req_state[idx].height = info->height; + + if (info->width && info->height) { + g->enabled_output_bitmask |= (1 << idx); + } else { + g->enabled_output_bitmask &= ~(1 << idx); + } + + /* send event to guest */ + virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); + return 0; +} + +const GraphicHwOps virtio_gpu_ops = { + .invalidate = virtio_gpu_invalidate_display, + .gfx_update = virtio_gpu_update_display, + .text_update = virtio_gpu_text_update, + .ui_info = virtio_gpu_ui_info, +}; + +static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIOGPU *g = VIRTIO_GPU(qdev); + + g->config_size = sizeof(struct virtio_gpu_config); + g->virtio_config.num_scanouts = g->conf.max_outputs; + virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, + g->config_size); + + g->req_state[0].width = 1024; + g->req_state[0].height = 768; + + g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); + g->cursor_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_cursor_cb); + + g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g); + g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g); + QTAILQ_INIT(&g->reslist); + QTAILQ_INIT(&g->fenceq); + + g->enabled_output_bitmask = 1; + g->qdev = qdev; +} + +static void virtio_gpu_instance_init(Object *obj) +{ +} + +static void virtio_gpu_reset(VirtIODevice *vdev) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + struct virtio_gpu_simple_resource *res, *tmp; + int i; + + g->enable = 0; + + QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { + virtio_gpu_resource_destroy(g, res); + } + for (i = 0; i < g->conf.max_outputs; i++) { + g->req_state[i].x = 0; + g->req_state[i].y = 0; + if (i == 0) { + g->req_state[0].width = 1024; + g->req_state[0].height = 768; + } else { + g->req_state[i].width = 0; + g->req_state[i].height = 0; + } + g->scanout[i].resource_id = 0; + g->scanout[i].width = 0; + g->scanout[i].height = 0; + g->scanout[i].x = 0; + g->scanout[i].y = 0; + g->scanout[i].ds = NULL; + } + g->enabled_output_bitmask = 1; +} + +static Property virtio_gpu_properties[] = { + DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_gpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + vdc->realize = virtio_gpu_device_realize; + vdc->get_config = virtio_gpu_get_config; + vdc->set_config = virtio_gpu_set_config; + vdc->get_features = virtio_gpu_get_features; + vdc->set_features = virtio_gpu_set_features; + + vdc->reset = virtio_gpu_reset; + + dc->props = virtio_gpu_properties; +} + +static const TypeInfo virtio_gpu_info = { + .name = TYPE_VIRTIO_GPU, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOGPU), + .instance_init = virtio_gpu_instance_init, + .class_init = virtio_gpu_class_init, +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_gpu_info); +} + +type_init(virtio_register_types) + +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 48); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h new file mode 100644 index 0000000..e24df45 --- /dev/null +++ b/include/hw/virtio/virtio-gpu.h @@ -0,0 +1,147 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#ifndef _QEMU_VIRTIO_VGA_H +#define _QEMU_VIRTIO_VGA_H + +#include "qemu/queue.h" +#include "ui/qemu-pixman.h" +#include "ui/console.h" +#include "hw/virtio/virtio.h" +#include "hw/pci/pci.h" + +#include "hw/virtio/virtgpu_hw.h" +#define TYPE_VIRTIO_GPU "virtio-gpu-device" +#define VIRTIO_GPU(obj) \ + OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) + +#define VIRTIO_ID_GPU 16 + +#define VIRTIO_GPU_MAX_RES 16 + +#define VIRTIO_GPU_MAX_SCANOUT 4 + +struct virtio_gpu_simple_resource { + uint32_t resource_id; + uint32_t width; + uint32_t height; + uint32_t format; + struct iovec *iov; + unsigned int iov_cnt; + uint32_t scanout_bitmask; + pixman_image_t *image; + QTAILQ_ENTRY(virtio_gpu_simple_resource) next; +}; + +struct virtio_gpu_scanout { + QemuConsole *con; + DisplaySurface *ds; + uint32_t width, height; + int x, y; + int invalidate; + uint32_t resource_id; + QEMUCursor *current_cursor; +}; + +struct virtio_gpu_requested_state { + uint32_t width, height; + int x, y; +}; + +struct virtio_gpu_conf { + uint32_t max_outputs; +}; + +struct virtio_gpu_ctrl_command { + VirtQueueElement elem; + VirtQueue *vq; + struct virtio_gpu_ctrl_hdr cmd_hdr; + uint32_t error; + bool finished; + QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; +}; + +typedef struct VirtIOGPU { + VirtIODevice parent_obj; + + QEMUBH *ctrl_bh; + QEMUBH *cursor_bh; + VirtQueue *ctrl_vq; + VirtQueue *cursor_vq; + + int enable; + + int config_size; + DeviceState *qdev; + + QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; + QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; + + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT]; + struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT]; + + struct virtio_gpu_conf conf; + int enabled_output_bitmask; + struct virtio_gpu_config virtio_config; + + QEMUTimer *fence_poll; + QEMUTimer *print_stats; + + struct { + uint32_t inflight; + uint32_t max_inflight; + uint32_t requests; + uint32_t req_3d; + uint32_t bytes_3d; + } stats; +} VirtIOGPU; + +extern const GraphicHwOps virtio_gpu_ops; + +/* to share between PCI and VGA */ +#define DEFINE_VIRTIO_GPU_PCI_PROPERTIES(_state) \ + DEFINE_PROP_BIT("ioeventfd", _state, flags, \ + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), \ + DEFINE_PROP_UINT32("vectors", _state, nvectors, 4) + +#define DEFINE_VIRTIO_GPU_PROPERTIES(_state, _conf_field) \ + DEFINE_PROP_UINT32("max_outputs", _state, _conf_field.max_outputs, 2) + +#define VIRTIO_GPU_FILL_CMD(out) do { \ + size_t s; \ + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + &out, sizeof(out)); \ + if (s != sizeof(out)) { \ + qemu_log_mask(LOG_GUEST_ERROR, \ + "%s: command size incorrect %zu vs %zu\n", \ + __func__, s, sizeof(out)); \ + return; \ + } \ + } while (0) + +/* virtio-gpu.c */ +void virtio_gpu_ctrl_response(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + struct virtio_gpu_ctrl_hdr *resp, + size_t resp_len); +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd, + enum virtio_gpu_ctrl_type type); +void virtio_gpu_get_display_info(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd); +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, + struct virtio_gpu_ctrl_command *cmd, + struct iovec **iov); +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count); + +#endif diff --git a/trace-events b/trace-events index fb58963..a2c25b8 100644 --- a/trace-events +++ b/trace-events @@ -1083,6 +1083,20 @@ vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x" vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x" vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" +# hw/display/virtio-gpu.c +virtio_gpu_cmd_get_display_info(void) "" +virtio_gpu_cmd_get_caps(void) "" +virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" +virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" +virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" +virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x" +virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x" +virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x" +virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x" +virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d" +virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x" +virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 + # savevm.c savevm_section_start(const char *id, unsigned int section_id) "%s, section_id %u" savevm_section_end(const char *id, unsigned int section_id) "%s, section_id %u" -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 3/8] virtio-gpu-pci: add virtio pci support 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 2/8] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 4/8] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann ` (4 subsequent siblings) 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin This patch adds virtio-gpu-pci, which is the pci proxy for the virtio gpu device. With this patch in place virtio-gpu is functional. You need a linux guest with a virtio-gpu driver though, and output will appear pretty late in boot, once the kernel initialized drm and fbcon. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- default-configs/x86_64-softmmu.mak | 1 + hw/display/Makefile.objs | 1 + hw/display/virtio-gpu-pci.c | 80 ++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.h | 15 +++++++ include/hw/pci/pci.h | 1 + 5 files changed, 98 insertions(+) create mode 100644 hw/display/virtio-gpu-pci.c diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 75a123a..1027916 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -10,6 +10,7 @@ CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_VIRTIO_GPU=y +CONFIG_VIRTIO_GPU_PCI=y CONFIG_VMMOUSE=y CONFIG_SERIAL=y CONFIG_PARALLEL=y diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 29f179f..df51ec2 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -35,3 +35,4 @@ obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o +obj-$(CONFIG_VIRTIO_GPU_PCI) += virtio-gpu-pci.o diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c new file mode 100644 index 0000000..0b7304e --- /dev/null +++ b/hw/display/virtio-gpu-pci.c @@ -0,0 +1,80 @@ +/* + * Virtio video device + * + * Copyright Red Hat + * + * Authors: + * Dave Airlie + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ +#include "hw/pci/pci.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-pci.h" +#include "hw/virtio/virtio-gpu.h" + +static Property virtio_gpu_pci_properties[] = { + DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), + DEFINE_PROP_END_OF_LIST(), +}; + +static int virtio_gpu_pci_init(VirtIOPCIProxy *vpci_dev) +{ + VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vgpu->vdev); + VirtIOGPU *g = &vgpu->vdev; + int i; + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + if (qdev_init(vdev) < 0) { + return -1; + } + + for (i = 0; i < g->conf.max_outputs; i++) { + g->scanout[i].con = + graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); + if (i > 0) { + dpy_gfx_replace_surface(g->scanout[i].con, NULL); + } + } + return 0; +} + +static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->props = virtio_gpu_pci_properties; + k->init = virtio_gpu_pci_init; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER; +} + +static void virtio_gpu_initfn(Object *obj) +{ + VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj); + object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + +static const TypeInfo virtio_gpu_pci_info = { + .name = TYPE_VIRTIO_GPU_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOGPUPCI), + .instance_init = virtio_gpu_initfn, + .class_init = virtio_gpu_pci_class_init, +}; + +static void virtio_gpu_pci_register_types(void) +{ + type_register_static(&virtio_gpu_pci_info); +} +type_init(virtio_gpu_pci_register_types) diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 1cea157..3e7fcd5 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -24,6 +24,7 @@ #include "hw/virtio/virtio-balloon.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-9p.h" +#include "hw/virtio/virtio-gpu.h" #ifdef CONFIG_VIRTFS #include "hw/9pfs/virtio-9p.h" #endif @@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VirtIORngPCI VirtIORngPCI; +typedef struct VirtIOGPUPCI VirtIOGPUPCI; /* virtio-pci-bus */ @@ -198,6 +200,19 @@ struct VirtIORngPCI { VirtIORNG vdev; }; +/* + * virtio-gpu-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" +#define VIRTIO_GPU_PCI(obj) \ + OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) + +struct VirtIOGPUPCI { + VirtIOPCIProxy parent_obj; + VirtIOGPU vdev; +}; + + /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index c352c7b..a55d8b3 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -81,6 +81,7 @@ #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 +#define PCI_DEVICE_ID_VIRTIO_GPU 0x1010 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 4/8] virtio-vga: add virtio gpu device with vga compatibility 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann ` (2 preceding siblings ...) 2014-09-23 13:28 ` [Qemu-devel] [PATCH 3/8] virtio-gpu-pci: add virtio pci support Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 5/8] virtio-vga: add '-vga virtio' support Gerd Hoffmann ` (3 subsequent siblings) 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin This patch adds a virtio-vga device. It is simliar to virtio-gpu-pci, but it also adds in vga compatibility, so guests without native virtio-gpu support can drive the device in vga mode. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- default-configs/x86_64-softmmu.mak | 1 + hw/display/Makefile.objs | 1 + hw/display/virtio-vga.c | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 hw/display/virtio-vga.c diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 1027916..ca04470 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -11,6 +11,7 @@ CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_VIRTIO_GPU=y CONFIG_VIRTIO_GPU_PCI=y +CONFIG_VIRTIO_VGA=y CONFIG_VMMOUSE=y CONFIG_SERIAL=y CONFIG_PARALLEL=y diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index df51ec2..31e0216 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -36,3 +36,4 @@ common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o obj-$(CONFIG_VIRTIO_GPU_PCI) += virtio-gpu-pci.o +obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c new file mode 100644 index 0000000..83eda0d --- /dev/null +++ b/hw/display/virtio-vga.c @@ -0,0 +1,169 @@ +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "ui/console.h" +#include "vga_int.h" +#include "hw/virtio/virtio-pci.h" + +/* + * virtio-vga: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_VGA "virtio-vga" +#define VIRTIO_VGA(obj) \ + OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA) + +typedef struct VirtIOVGA { + VirtIOPCIProxy parent_obj; + VirtIOGPU vdev; + VGACommonState vga; +} VirtIOVGA; + +static void virtio_vga_invalidate_display(void *opaque) +{ + VirtIOVGA *vvga = opaque; + + if (vvga->vdev.enable) { + virtio_gpu_ops.invalidate(&vvga->vdev); + } else { + vvga->vga.hw_ops->invalidate(&vvga->vga); + } +} + +static void virtio_vga_update_display(void *opaque) +{ + VirtIOVGA *vvga = opaque; + + if (vvga->vdev.enable) { + virtio_gpu_ops.gfx_update(&vvga->vdev); + } else { + vvga->vga.hw_ops->gfx_update(&vvga->vga); + } +} + +static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) +{ + VirtIOVGA *vvga = opaque; + + if (vvga->vdev.enable) { + if (virtio_gpu_ops.text_update) { + virtio_gpu_ops.text_update(&vvga->vdev, chardata); + } + } else { + if (vvga->vga.hw_ops->text_update) { + vvga->vga.hw_ops->text_update(&vvga->vga, chardata); + } + } +} + +static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +{ + VirtIOVGA *vvga = opaque; + + if (vvga->vdev.enable) { + if (virtio_gpu_ops.ui_info) { + return virtio_gpu_ops.ui_info(&vvga->vdev, idx, info); + } + } else { + if (vvga->vga.hw_ops->ui_info) { + return vvga->vga.hw_ops->ui_info(&vvga->vga, idx, info); + } + } + return -1; +} + +static const GraphicHwOps virtio_vga_ops = { + .invalidate = virtio_vga_invalidate_display, + .gfx_update = virtio_vga_update_display, + .text_update = virtio_vga_text_update, + .ui_info = virtio_vga_ui_info, +}; + +/* VGA device wrapper around PCI device around virtio GPU */ +static int virtio_vga_init(VirtIOPCIProxy *vpci_dev) +{ + VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); + VirtIOGPU *g = &vvga->vdev; + VGACommonState *vga = &vvga->vga; + int i; + + qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus)); + if (qdev_init(DEVICE(g)) < 0) { + return -1; + } + + vga_common_init(vga, OBJECT(vpci_dev), false); + vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev), + pci_address_space_io(&vpci_dev->pci_dev), true); + + for (i = 0; i < g->conf.max_outputs; i++) { + if (i == 0) { + g->scanout[i].con = + graphic_console_init(DEVICE(g), i, &virtio_vga_ops, vvga); + vga->con = g->scanout[i].con; + } else { + g->scanout[i].con = + graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); + dpy_gfx_replace_surface(g->scanout[i].con, NULL); + } + } + + pci_register_bar(&vpci_dev->pci_dev, 2, + PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); + + return 0; +} + +static void virtio_vga_reset(DeviceState *dev) +{ + VirtIOVGA *vvga = VIRTIO_VGA(dev); + vvga->vdev.enable = 0; + + vga_dirty_log_start(&vvga->vga); +} + +static Property virtio_vga_properties[] = { + DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, vdev.conf), + DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), + DEFINE_PROP_UINT32("vgamem_mb", VirtIOVGA, vga.vram_size_mb, 16), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_vga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->props = virtio_vga_properties; + dc->reset = virtio_vga_reset; + dc->hotpluggable = false; + + k->init = virtio_vga_init; + pcidev_k->romfile = "vgabios-virtio.bin"; + pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU; + pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA; +} + +static void virtio_vga_inst_initfn(Object *obj) +{ + VirtIOVGA *dev = VIRTIO_VGA(obj); + object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + +static TypeInfo virtio_vga_info = { + .name = TYPE_VIRTIO_VGA, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(struct VirtIOVGA), + .instance_init = virtio_vga_inst_initfn, + .class_init = virtio_vga_class_init, +}; + +static void virtio_vga_register_types(void) +{ + type_register_static(&virtio_vga_info); +} + +type_init(virtio_vga_register_types) -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 5/8] virtio-vga: add '-vga virtio' support 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann ` (3 preceding siblings ...) 2014-09-23 13:28 ` [Qemu-devel] [PATCH 4/8] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 6/8] virtio-vga: add vgabios configuration Gerd Hoffmann ` (2 subsequent siblings) 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin Some convinience fluff: Add support for '-vga virtio', also add virtio-vga to the list of vga cards so '-device virtio-vga' will turn off the default vga. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- hw/pci/pci.c | 2 ++ include/sysemu/sysemu.h | 2 +- vl.c | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 6ce75aa..3328d98 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1653,6 +1653,8 @@ PCIDevice *pci_vga_init(PCIBus *bus) return pci_create_simple(bus, -1, "VGA"); case VGA_VMWARE: return pci_create_simple(bus, -1, "vmware-svga"); + case VGA_VIRTIO: + return pci_create_simple(bus, -1, "virtio-vga"); case VGA_NONE: default: /* Other non-PCI types. Checking for unsupported types is already done in vl.c. */ diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index d8539fd..3741855 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -107,7 +107,7 @@ extern int autostart; typedef enum { VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, - VGA_TCX, VGA_CG3, VGA_DEVICE + VGA_TCX, VGA_CG3, VGA_DEVICE, VGA_VIRTIO, } VGAInterfaceType; extern int vga_interface_type; diff --git a/vl.c b/vl.c index dc792fe..4cbd401 100644 --- a/vl.c +++ b/vl.c @@ -249,6 +249,7 @@ static struct { { .driver = "isa-cirrus-vga", .flag = &default_vga }, { .driver = "vmware-svga", .flag = &default_vga }, { .driver = "qxl-vga", .flag = &default_vga }, + { .driver = "virtio-vga", .flag = &default_vga }, }; static QemuOptsList qemu_rtc_opts = { @@ -2108,6 +2109,11 @@ static bool cg3_vga_available(void) return object_class_by_name("cgthree"); } +static bool virtio_vga_available(void) +{ + return object_class_by_name("virtio-vga"); +} + static void select_vgahw (const char *p) { const char *opts; @@ -2134,6 +2140,13 @@ static void select_vgahw (const char *p) fprintf(stderr, "Error: VMWare SVGA not available\n"); exit(0); } + } else if (strstart(p, "virtio", &opts)) { + if (virtio_vga_available()) { + vga_interface_type = VGA_VIRTIO; + } else { + fprintf(stderr, "Error: Virtio VGA not available\n"); + exit(0); + } } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; } else if (strstart(p, "qxl", &opts)) { -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 6/8] virtio-vga: add vgabios configuration 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann ` (4 preceding siblings ...) 2014-09-23 13:28 ` [Qemu-devel] [PATCH 5/8] virtio-vga: add '-vga virtio' support Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 7/8] virtio-vga: add vgabios binary Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 8/8] virtio-gpu: add to display-vga test Gerd Hoffmann 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Add seavgabios configuration for virtio-vga, hook up the new vgabios in the makefiles. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- Makefile | 2 +- roms/Makefile | 2 +- roms/config.vga-virtio | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 roms/config.vga-virtio diff --git a/Makefile b/Makefile index b33aaac..27aa63f 100644 --- a/Makefile +++ b/Makefile @@ -337,7 +337,7 @@ bepo cz ifdef INSTALL_BLOBS BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ -vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ +vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \ acpi-dsdt.aml q35-acpi-dsdt.aml \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ diff --git a/roms/Makefile b/roms/Makefile index 610b534..c76cd5b 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -1,5 +1,5 @@ -vgabios_variants := stdvga cirrus vmware qxl isavga +vgabios_variants := stdvga cirrus vmware qxl isavga virtio vgabios_targets := $(subst -isavga,,$(patsubst %,vgabios-%.bin,$(vgabios_variants))) pxerom_variants := e1000 eepro100 ne2k_pci pcnet rtl8139 virtio pxerom_targets := 8086100e 80861209 10500940 10222000 10ec8139 1af41000 diff --git a/roms/config.vga-virtio b/roms/config.vga-virtio new file mode 100644 index 0000000..9a78983 --- /dev/null +++ b/roms/config.vga-virtio @@ -0,0 +1,6 @@ +CONFIG_BUILD_VGABIOS=y +CONFIG_VGA_BOCHS=y +CONFIG_VGA_PCI=y +CONFIG_OVERRIDE_PCI_ID=y +CONFIG_VGA_VID=0x1af4 +CONFIG_VGA_DID=0x1010 -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 7/8] virtio-vga: add vgabios binary 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann ` (5 preceding siblings ...) 2014-09-23 13:28 ` [Qemu-devel] [PATCH 6/8] virtio-vga: add vgabios configuration Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 8/8] virtio-gpu: add to display-vga test Gerd Hoffmann 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Add prebuilt vgabios-virtio.bin binary. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- pc-bios/vgabios-virtio.bin | Bin 0 -> 37376 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pc-bios/vgabios-virtio.bin diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin new file mode 100644 index 0000000000000000000000000000000000000000..7febcb660b23ba1fb6d0d52d9f08458b86cd8c15 GIT binary patch literal 37376 zcmeHwe|%I$mhbH(B%RRYb|7GbE%Z2m$Otxy7_=pU5D=MQYYaL%Xdt8-H400*NgP86 zCed_47<YGeX5E?H=a1R<acA8p%ewrU9qbS$1kCcw872yYQQ6RK#}L7R5MuJa=TzPP z5n$f#`|Nvv%?0}2x^?Q*sZ*!Uud1tszgQCb<iR{``1RL*db4Cfz9tHV|35@QZNNK8 z{8G!&w81v-Ekb|ynDBonny(~oZW)@i`E#u^JX#$4RDbu7M>M@Ql%i>P*C+fP;t8>0 zUxLE2Toiaj;|jCzpY}AYu!!bPt4Q4^W(BqerV9T!i%Ix<T_$hl`b<}%{-c1nU(|H= z0O4cb2`BtZy4Zu>wXOTa(y8?mYw<AEpI)b-gC}FUcvPSh{PBP25&ryM;om3bepEIA z-R4=v{T>jWXA!0rk1*x+dc>s_7LTaeXw|$kw(bK=z8OD0wEARA$JUQ8{CsPNM-1g# zJtC0+8}smkcHs}iW8Cdivg1cVV&!DBs5#RI@bUr4GD%5I_iSPmxS?r7V)JK1LqnSI zpAfT#g#PnOR?*yL75?)g^@`Yh2vr)WE<7qWf1v%PPR}cTBmAvma~HRs!i{GgN6UR^ zNz6MTMyXbL9b)rg)yj8D91CqZx-}qnX|E8@CSTz4zmM%75I+--i<<qj4eC+j=@U;y zCdi=KDr)+4?@jo%>VMTD^c@!f>7A2|r;~X4{u3j@7O{5(s1m>AU;pn!^SMM(a~4y0 zR2&Op;t~L88BMd$4IY<tC)6JkHJ|DpaUiePgqGEplf9!v&1VTf3aO#V+C%T_KN25) zhPDq32^09~&kthKnnjM-ok;z?CN5pZ+q^S`exgTwSaL?}qISanmH4m|Z*zt)RfWC6 z)Q^Vy&~UHOaFB2Vq;UnePNXUA=3XEcK|sE5K%(z9Fv@B$3LKg#8q-UQMcqNY_KGQf zirvD00JyZ7o`xLaQGf`1Ths(n=wX{jG;iESoh^psL-hQ4KZhXhT%6A0i0a1jBzp0v z6$GCUrjLaQ!q{Zb0O*Q$JPnUps{0eYPgeIQ>9q-_>iz`1?l}_xeD8@_m=1l%Ba^`A z#=N)P!Mg|1CRyY{Vtw00%@wonlP$+lm%mLkf0~Fsj*I5c&{<R7d)!H5-aGE#ecyy` z0zQ4mqXwGZZvc}2p4ejsV}TL1i9qpy4|32*18TDW8a3J$$YKN~$T6K4{*M6Sdj~7o z9XvBY!+LOns0m?V>F)xCAM?@yiFXGN42WOSyb;J^yO`UeH~oYQ4`Q_vEbuH&!V@^w zSon@G9d!r)azNyU4^xY$CZgsvEzF-|ISbPV5)Co;ZGL1VdFT)`bMK0G%El4pZ$qW% z@3zt^2ErC`2^eZNzO8vD3jbx{|CnIFklR4_P(JXOFc8y)@W&7ZcZ?{=+4nb#y1)xJ zh&}ruHDXtSu4(7C9~QfkFsSgiu=FrGh?}TsOOP<<gue~T7K)-RY5U=GS81)9Zs-E& ztwx{4<In5z`18*g$O+du^a0$sB|*R9rlDWiV*;0HCE|550f7fQ@~p%TtUmvWUSfPr zC)l|o01`$*@1zS;D;Rl^xRqzd%MrrVOAUe~Rrjtq<GowFuf0Arw3TF=7BMs<el`X@ zjd@*LKHk~^{rEA78Wxe#r!{#&N4RA;(M0C9q;t-|x$W)UVs{$IeB0zr_~-N}Ka$0s z!vrR|hua7%mEu>RWc!|W00PZ>xG@^2$hIgiu?DTx{U+~?>oZ_juy9~VAg>E^Okq11 zNOO}3nEPp+9+cg&PKja=QVTv*-y&*0&t|PPN$ko&ODI(TX|T?Ww#OjsQ~l$L@N#Oy zI6vJQ=hSJ{pP9Um)(o0AJY0P_r98j-%A|6L9D0(PGuI^MHWSyq<46$2`?SEQf9R~H z$A-dCye&|O@1mD0P^aMpF(0MFqWN;7Sc1vP$EvzCNLCG|Rf<v?=DLwAogrHz&&8W3 zHsE9x{U5r69}faw2YN|y2mcokwTj(L0??6WRXE3Bg`NZZSmvYlTQbH^1_5-eB|5gH z_J{@D5UoxOVCj%ZZR@Fq)`78xjAB(J<2MYo(p2ybT0s>x<qqH>;12%9puyCs{)u&( zJ2(mWTDFbGG9;V-A}mRNH$dCArO+!X@r;nYI4PPxhi+~9{&*9*&LM;-C4sP=0UF1k z_+<_{-U`*x<Q|$@KMw9f%hbkk4`_rCP{%Pickt#*c>C6Or4ONuIdiL~8@)G+Js*>( zZ4Y#N>hp%`+j_P)ch@&>{}^vP4S7R7^=-o69V0i)<5n{Fk%slnSa?149f0i_#!Q0d ze&So8t4q`deThpSif?s*rP~8N=<rex)`Mvn7BwZTHDFy1h&=~DGxb(?(K|)#IY=Ye zdSI%jK2hFsP3oQiAxIR<!Y8g$Yz5+B%*2+Xq(hd%CV{8Vki99q><-osiSL1y%bxn& zvAFl+J|6cgxZ5CyD+c0Oay5BvG2{_l4T+M-9xmjX)I9-%y$*Q~dm7whJ@tj(;65Jr zLELS)50RzQcic}D?^6_i;|}^j@wJG02xA0fe`K;C5<PfvQkXswbFb)4FOjfZ*m6`c z0R9E>;462qc2GP{Jr#Z>o;{vVPkHCX(}ACmz?0=h`GR;hU<de*5~}HKb3f+hXib0i zhGelT8*ebn7x3>q{(W_g9-0TSgmXjXLlNS(IcQOoe0|kqNe;twkm`n8<A>+t|G?uf z1iXJm@NJV``)tC+{U+adxVw30G-yD*_Q3=(>!4KAp|K`+@aO$3I%LSCp5NL^5<_c_ zpP;r_KdVv#uK`s^+<r(sB@xoSgao9{#|k>%Bli57ac<4)0m6kNM?jy|Tu$<x-oBsM zz5UnSo~?PksLD-s9z?5h6D_KKtoHL%BO9f0qw&5oV%9}04R`Q+14iAQ-xiBR&0wbQ zEcZ<|gb+~2N8&oZn{lN2J|%P23uW!`znBAkJ_}FvxeMqgmwpz~PhRNwpzNUmB!jF! zGqGY!?LDXHCp7uJTbm)jxv7|NGOA`}<>_tXi#cLf22H)cAByxK2A$y@8^M_-(a}&P z#__)23uV}9ItMoo{RU=hpGZ9__Uywjde9I|YRJ7&>E{fI_M$@g2-pDS%DgGNqB!!o zYP1v!OzAOF3$qSxKOCXsZbgSABGuQ0VflJ#%4u2BO!jaA^N&f9k8oy)&8kGc<fF+X zo4Jcf0)xP?@r>~IK`$rhwKGg&^I39Uyj4Vw*lj1C>|H`jfLsY_0t{z@K!~wG()5B| z>?Y$O_SWLpfWXAPv4@-XvRmQ{Vj>sajA=v-9P~<!)QIpen@r_5EGAi8G)?Tfjr)u& zfxpzY(fl((H0q#uUr|-qYXpCWfkHhEtZAJ=)B8jd-bO)D*cc_L5hU%-0Ssi}tv!;a z#$}TgnSO)J#%0rpOn*8eUqv4gVuFL(n0MxFxcfiVuynmkrB<h<Nu5AMlef1?HNMES zy;VI?z_mOP+UkH<!@lRNgYIC*W%2md15(UiPQ<)Lw19VR1YN@-Olm6&+BHzj?iY`- za$W>2K<c|kY;H}$UEF$F_%G@87l{@5XD&9I_1Z5GC%v(-5T3DKdm8VXX5U%;A0{8d zz6j@Aw6Gg8MBXv`%ICHp`BKWNKN$|)Z_((<1hE_S8tDq}cyetRUO_@D_~9JEQ6goM z=KCo8hHT$B@nVa~H+C3uxJu{34~m-B7^DE=z9V=U=w_e+^2TJi-|SEsz0!PO?Gp;w z<u66e0eC8iPp_qu{S?0CJSuAXQ_D$xEO5?*@A2n7F}?!4F}RogN#5m~(s57lmTr1N zJmB?(sg&%!x$<`0Q@kVD&kNe2qKD+84GT+m2meYHGiC8*RfPXYwJ;py9|kS5xJDHb zc~I^5R53{w5oiM#HLxu!Law3M*w%l5)ahjzsfp%Lk~awv7_{&Sn*6$pRcUHu%fes5 zOQUs9`55?8p>Yxsd~I{>K}7l-+*e;t^g6=OlyL90@HkYuldEAIp}jVMx_v1~2q0~A zG=@{;Cy}i-<jQx8JNWelay`e8>nZ)E4tG%d8ZH|f-%HSHiQ(@UVnAAiB!`?`KL9;Q zz3e;zH~6UG`yQ3P@8e8+)ZLBvbMD~ouZ`}#PFAxwgK2OOr4(}ynCGP5qbr%BV5ecv z5f0m~<44zYn`4Jn=nme5VKr~F2>&5cs4zNY1?%&Aw~eA#s)Q&KgBVSq?1c0pqBrxn z&moycRQy$hitsZG>?6-Qj#y^L0g6`1`<L8lredm5)OYq`42V_UZBcA8GB5Q00Keym zf#c~!te3~(XQ{~_mQW(bBlehgp1ce);E$Y_coC^8c7d5wG~~Y!8)N*iiji;zWA8r~ z;r=FW|MPEXGGn<<10qK?KB%HOstb4@FhF^*B<*r6O-a8sScR|%t>uJ8_+UWB)IpOD zA7uT$!GLd+VJi>}u7YAio>Z&uPbt5}cuyh@)$-lZZlI`dYYv&~+c9(GtOm%?$BUf` zUl3A0z>&*D1S#a2awPfgN4N)QrgI4^Dh>-1B246DO-Ca#jQCT3rCw!TrI%PB-p|2+ zVGr~jaAy6K=|mFub6S7BB9)RmKKL2_@6T~V;WtcNrDc8ObGd^8!rtNzRsp<O?4=l5 zafao}m^Xy;he$Y;kD_xiE>X&{Rm5QhPIPF64oGk%dZ(AC4z}sFi3y>%Mz~=4jwiX2 z^}3&o078s3>iC8>kQppUf{T?-DMx)LLT7zvE*ObqA7>2VL^R}DkV3BQ)(F)KlMAj$ z16iYj(Nf}(3T{n8TDmUa``Yj-r}bdkDBl6rLfyj$(gY=2Wje20yw4FWl;N$%2%uYh zNKOtGDd!!{3&)HW3!t>kzLV^MCHelrNQA_thR%id!BLiu?7x0V@-&M^u;Y<L7!;uD zhYB=_-Q3x&&B%p{)ZZaBS<`3sb;J-z5q}>%0h8+N-SD3qSfBcm@a0N$lEzD5qQ0{L zAxYzlaM}DD&wzguJpPT{p62Je6Y+W@JTE^Svby8mZ%6Y!`c6*#Yz$ubg?NCV5Mh`$ z2E!ey*B^!^NcK}Y4(x}gAxCx+vxHf(3pY|}Wtgqp3C%&8t$=XDpa2!(6tG)E;J+}4 zz}BKLHiy~<ArcEHKSR#oQY(IPlb|_3UtTv5r5lK7t@{rh`vO=oP4E5=^Xme%A46#< zpq!~*I|=DhNWf*zn%358)t{QYsUER8uUB(Gig#(dBJ+(f!sMHUS+~-hU|sD^;hZw& z0NL#iu>>w7e{J&Ae-{%a=c6-pDFJKR`to^h0xF(u8x%FoSP9V<iLotChkl(fj0SYJ z%y%D28Vi`Gf$;kei<&No7K9BV&?QpO8(qfHjQO{Q$`H&Qk7<?|p(3{7X`|uG=fO}C zZ@)E^mEdVuI+{lgzvELAhTSYo&_~TEVYYTa(wkh;p1>$KBY~LOhlB(aS2C0q5Ea;& z|NTm)3MMpvL9<NraRSv!swm5PMq|Muh93}qT0$gMlxT%aH9`<su;Bd}I1$Y&Va2RJ zF`+q3h@k>0?Ms_9n_GDf>yGQS>r4<?h4~}+q*7WFecj<s$oa%$=g<;ziYz9YUxt|C zIoFPD3Mr2d#fm3MRji0YmAiv){0E6BnDImE6Rjb=oA;^bC?+NAam2!XftYDpsD;{L zDWKD(>AW0CXCdEzNUAIE0#}mv2QG5s%SL-`ynmyTbC-Yunh9=Kcns17yID;&8}7^R zww&Z-?8)%ca?#OB>7_BjkL?EX(b%~|bDD)-&AX7&VzjU!rE&t0lRqE+l-treZWShS zEqL{c<@_`OEK#fV$7d8PqB=QZ?%88%A@6WE*rXw4*_t#GTK1stYtVEj+wN(|IQwZq z!w)#e&*q5DlCCG^#U?}ekdF7~W3zyqn!Ho);NJ|vRwa7;E4~0tJFt%jHxDDcXqeck zZ`2Ws(FA5vf42<@bkagQ3a#+<kP(5mj)EDA3a$D*t$9IA24h~0rM-VL$cS2D!%UHn z21a@6^DiLJWhQqFcMI<4JPn0bPeXnt%E&(<nbVMG$Nej)uSD#Z&OrGqlmWwu9<(Vm z10J3m(k&fulAqv#le0WxNbJo4#}Hz_@qi|$E$^H=*o|CZE83vXLbU5c0vB)g&BWxU zk?_)p^2wCbCZ)b}BX+Ye&HjxLRaBgZTR?Rf!&lsu;hP`-?2mKWIrx9iX<}|4hD@yL zAtuARFq4NaU6;vl`C96a)?*=H2ev++G!%x=fI-#g_u!r>*`E(K=l6oWBN0)6y<kf{ zV8Bw`fdg5|d~^M=dd`lMNioK2jk1?KDsbweFp=yb+TN?d)OxBn_GsP|;m5#{-mf|A z@c4aj!u1{4^JvJ&cGW7_HOY63ua|08T%a85cnUqS>qRosnAdaRAH_24N)-mfpV2Zg zD2S{OL#%Sh`>D@A3gqU9{7Tw(^v}Jd*F0uIYJheWu$kZ+S9|b<(N4~Byip0Ov=2t6 zIy?$iN2NLF6$|}gFne|eh(CnzkBnj7F5cH_%KHuF%|!EAESZg;MY_b20XMKR{2SY8 zP=!b3@_<f0karXkNvyGGFN^`#bCX>u`j5#rLhk%|M`7#HWM>}j-sZiBZ8l%K-t@W# zhU~%w=Di17YEMSOiS*7<&HDg^q0>ad08-BXfhrmnj_QJ#91^>#(GxjT`i?7P3hVm3 zSSp2xUq9RAxufuqr~Z*qT^xIxeFwu+0d_LlhTuEANdzAYcbfVmZA$&U^aruXGn98G z^ym=gCFiPnDZuvbILccb_aQp9e-F{=tzyspg&H<>8)>N>#Kw(}_8b-@gy$eqO&6Q{ z32gl*;UjoF^#pQUH^Qy~9Q&R7ZbOrk*wplWjwbUHV7p-FWA%&LP@;5}m@;I-=vRcw z;$m-7f~0#+2>%gxux*GUnKhVb=Dix$E6^mgvDXKo{0tL&CYHxrzplmhaAW?_7p7wN z=41BCv8CUI82j^09_RP(>WXF1%CEyCsnS!AiZGcw(uW+%M}${ySvVwB?%-Wa63#cU zf<{n!`7-G>Nlh1IFo+J$@QkAp@p%n4Z5kHd^o8U`&3*^>aJA00(&9iS`waHeNwY%p zVwZt6Yyq@w?$}6jts%V@@{8>?Y?JNioqKparCa6?Md};VdCTX#s(A>ZKW#!mH(n68 zLT;OWKt2zv(ZciMR(Lc`Zj-1R(zo`*Y#rCPUVugM7Y5zI`)Ow#PQOfSMb^*j2=<_% zfh3o8Kloi3gc!hY13b<y)E%rEL1D%S@o=aX$jA|@dI0({2$KqJz(xWZh7KIKS<636 zHW%@QJLn~|WF!4U`|m*l<wn?zX~@mM<MMDWYQI7S+Bc(h5L-8-VuoXyZeaQfxs*p~ zb3`Fv<ghKOM-QTp{h8pxHH^EVx=2~Wl))SwL5QTL1+xq`!JEW_gV}WlZ5*OQWQ!qt zS}j;C_mB&NSSF8x;tRrEe+(oeDF9EP6G=w#cz6yC#U1<ulzijzG^if4=Cy5wKJPcO z92+l))P8ba!)Z9O1Jw^77^)&s<ap|lv(AAY*}Biz>I=+0>N9(g+4KzNk{n)lR1dSn z={wdTLeh6skTKnnlYxv3G`&>!JD;$Lx|3cTct>uzA5+ql2f{z2t(v7_TIT;{?C)di zb~tv3Qw(-&HT@s47l3x;(7fZzQ;>1+-W8r)-Jj+iU)?{-H^I{iMfPo;0IwZEZ+&8T ztY;8=;W`*?h6GVA2^+7E8JU5puh(kz&1%h=vYN}Dp;o!rBU*d~f=)W<G008=@&mM; zN)rHydKj3%muEEGvDpEIOmq6L7p3?{pb6$-f+9d}svvvGHMox0kvC|rXMOOs*o71k z-0_!Tn&D*tPdyzsDTH^~ln3YN?4Wo8c>5t%moY%R=>z0-b|q#04Ju}=Ysi<uOBgf$ z9Y)<7z6r7nT~mMx99TlHkaY4l$fYa9<ikCNhf)9!rSP1mvCLL?5e@9#`#f875fe5* zf|@E!)t@GKN2@pYBXrEigf~?r@cQFtlAt??{mbCog?~w*p%nvwD_KaZ8nt(Wo@+@K zvBd)YdIdVADZgL*l8#jn=PzA=`Eh#cGia`o#FFqAo(2=#Q6p13KTPK;$TPWG@gk4d zBu~1T<*L<dJ58=BUNdKTL;r>~)Ck9phK8=sInW>AU^B=CY85p-PI#Ktms87caXF#! zkV_biEz&e_YcF^wnjT3z8pe9eJLe=y7l*O12O%)7Qr|eSm@wgqqO7U}6c#1?v&psE z`}n4tTr>6B9?ey(*Zxj(P0{OSn3$ezQ+h(PO|CM%)@0f=&9zRi%cMnKmLzMPJ@Q_G z%|J^0f%e2uwdV49XSyo9xuLW4=FZxKzGUnrB!!U;Z!yE8dtsz(Hlqi}gCNIrdZ95f z9?TtlVKB6tG4cwog^z<Fp7Tzl{=p#1Sb+T#Ma>sxckrEHgaVq<fwSQknNGk_xhWWa z7UiXqZtATk{2ja~H-QU_F+ksgT#cF=WoTi{WiIB@kAUEV@C*atNVK8p9?zrb5%a@} z4O3_(Y&666`l0Qc7L&%#Glw!r`ef!i_5=he6*61tV$GKi(USY^H{!9dPwiE^S^g6! zxufq)q}xy#mhVuRjee~3V;5`wzzu))4aCjC4JOM5xej%|neI)wQzZgSJY|aTV-{<i z4^yW_s_j)PxTYI`{=5OGlZV8bXBqfT0tS*syry#*q1kcn6zw6P4FdQ3Cc<yiUpitE z_icyUroZxQljmYyuh~}y-sM`<R@h8ndNG|Mt<mb};jH7AzQTBWx3u9m04obs=kIq1 z$9w_?ZXP7nw8^e2$x3`B_DqBW31{~-c)Tcll6py?tq{3A7jOrk`-Ho}2IfWdoq0FR zj?|s+{GRh+nFvs@Qg&qmw>$U~Y!cI^EJAVoo};E^<K#{mS}#mTe2iV_)Hb=DJHqz` zLrisItDm-P0h5#-2a@Uw(~u|7;@x8$sM`J;xpmF>Uz~_hQbRqi;dozIZcSr>^zdl_ zKA?bn5AF9>YnpEX8c`HHX0XjSnYfrnyRBLd?9t6}MX}3)04$6=umOYS@Rl$9BVoW< zwAz3#*WjvES&!Y!!9A75#FjnqIrm$_6UCbC<VUZW4Y?C*Dp)8cUSVZd^8u149T2wb z+Gsv}M*@P32}_AvtoeIJak8JcHpo&QhttD0a8_hPVzjZhKzkY3NWm#L$if4d_w{4( zV1=laTS5~O<RR72G{`L_kH|hky5UXMjZMPPm*ZH|PIm2sC@o5YKYs>q+Q5TksMjvs zpHzV&(w7^%S=h`-RX5~yhm*Djwhc{vbBShHaashuQ#81&BlEgx2O6GKm*%?(R@)D& zjji(rpud0Wn>ZJBK<rAv23GhEbg?J}MVWVne@X|broKhsc!!a<$)i<9GaQ|Gs|Y#} zshBPr6rAK^$0BJA9IJ8%zuSR?##_ZmYXAyItvEjeTQP-11SxHk7#~2qP%UbL4nV&7 z3Lv*#p894zB|=`up*q-<&P`L_^g|#H%E3{BS;kJtHDgD`?@e{9!0;@BVgI;g8U$_D z!KwA>tLSMjseY_QlpC}yM-Tv8#opdm@s5%Jse=?i`{%qJX;i{bfvIl_ZOcI%nzf2u zm30h_v}hY#OYv5vR(&PiYpcFu_1;d0-LfKpo54p*q*NB)%wh_sN9rKB$Pmm5gl<SM zL`knrA+tA8hM(0}5`Et>0?TpO5`|c#QD9kf`5E6?oGn%{<*eiG;0;&8w^UzA^4%=e z*o|tn7^eWlo@r0gI(hbE@fbQ-Mu#nFq3nWAz#&WIe77ILVsFGL0Dm(}pYZeEAb?1u zkw-&F)5b?lY4e9)ZR~=_!ms$)DGNTNfVL&T<a0Wo1#do^f=y$YT5kR{dHZ1;0~M)= zMGl&_A0d=t&u>74(l^u`9UY-<9c(1u&l;zu%|zMTW4vPSK#qkwj#Og#5e5P|fR{*v zZ2pXOLrp(~>!7$qht6^SDFLof&A}WAy)C6@`)}#c;;%5JJ*4k=+jH9u@^xEck2-!p zs+V@E-N6Ssqz=W2MvV6yjxWgrznCWPg6+TAmZ_TNplJ?Tu-2AMbu=Zdy)B8(J7I&< z+yh38=-GaRNcaRV(8xHV12q~t2c6Z1G~ORmR+(g<*I51>J+0ZnYHIdHWE3A0YtFFt z`z^n7Tx8=;s_T|M$k`S@+4TF#7(ZdBq*e2$X0iDo=&cre`Yb?(MSgDkz?U-{=lsk+ zx7T;mcI?K}t3kX<|2zNOHecG7HeNFmU-e59u&t$s*n#adOoNoHSpmq1*afXLL?Xh) zFYgO%^Xg(vCsX$FAH<WPX>^u|BvHZtn&1h&RF+t33kwaZ^}2o&ax`<$>n}lXCp<O1 zzDBNM{{`N}#8(qB1L@#_-1kpoz3ET~_kBG<{}J{!4u+HE+=9JHO*BCw74ySm$G`<n z3DB|MUOI9>iIo(Jk$P#zsit!ho|}8jF#K!A7m!diBc-uF)8I#Gv9Yem6$b;pgaBKy zq{yhiX<)9Udy6qV4pX74)=+`JUcgw_6%(tQgPG{2K&+X^T|7x$z$J-4E(4^rNzEpQ z8sUgJmN30iOZH3Hk06zKiGviByCO~0+S{wrTUBI$7A2F(Asax6+t0xs9Ks>N$-;IE zB|hl+XK+rMJ@;-5mfuTyf5qoGC*D<lJIT`uGFRAw)88$G0c~245_7g0FOidf7opm{ zD|$DOH-Oze-U(c@ibq*-fzA%_%tP{_)Zvo1BEvRF88-c;$A_X)usV^>Z6WxylA^Bp z?1-p2<NzzV$j3@hs6*ZMBAok$K?!WXj0aeh!1jmmKqs}grA~dbMB8$R@-(dBxA`Fl zM3K_)y{~fAN3ZFj8}o^WnvLBz>9w!GaYl9qoO*RKtUTBNB|&sjzNq#IIF*zO)N3Dt z2iSt4Qn-{u=|E%<kNG~uM;U{9?QFRA*bBm2<c=^^DCP15;0@XQf&|2spW`7njjVs| zai49=A^t=O9+n@Qcl9Zh{m45Lb`ntPmcwjf`-n6)+_c-ZQNnR{$_I5FvEQEh#U^UO zFu>9Ue2bB|fhEVpvn5XfbI!vEd;E(N*^8tsOwEB2VmAq$aX^mxwnqpfEU66aVBj>d zdwd))+||huXkh!c*iDXY6dM4h#RA+dc9Ui{01z9HcUF_vn-f|)i20-Q6T9wo8<U5O z^zp4^p>s&3AhX|#%|?s?rwm|8C%g0W^}564THx5x2#oeT98v;lhL=eSd+zx%9d#B6 z{t;oiA{K<ZYftKRKh@x|6Wl&R^;in#sD;!5ov^avVU3rC_+OweuvDQ{A9^NLJToMo zaXh1WhQ2=;S?v8*e0;@cE!2Szc$!VQNJaO3Q@)f|`!+_gu9x&RuY=}r63)f{$WJDX zhq?J$!=&S40js!AgU!?HEJNIsPg=pN8MnocB?2d@eq6FPvmqVl9Vk`W{Ant^4v4vJ z-jNutjlMX_3A2V0mp*1_P<IVaS#Ixnsw*-~8&W+7a_tYALa)QOtgxEOv74WRslw7k zM*HIa9OUm?b8n)6+a0uoC>TEMseUm78KYdQcS<DN?%f6V9v>P>{ia+AXsg`J@O)3> z(oFFBt0-_IfL|E~47rYVL*y}_xxISbiXkRZyH1kXhUJOmkKHu_%Q3lpGMy2r7*Re7 zG0QwUiSk2JsMJh{NdA`3qwF0KT48qKgyTag<vNb0)Q+LuklHtsLyOF=G`+Sf#brg7 zA|-UU8EY95M9Xex0bFwk8QC}-2|!Tu3#`*!%kv86LzMi0x<qA)=CINhBpL4E2apD| zW_?8R>tB!z4Y;nDh1tIV36-V=H+%T}4sBSGOkrF8k~{?|{69!1OX)4<^$qX6xyK6h z>qm>dpGd@Td=Jx+PT^laPV7B@)yoNDZ}KBdLJZ_Y?064iih(<wc1o}XCw7ww5p$20 zQA{_hW^l-Bkwo~N<f8Ifh|QOIpX4L)K5I!n46T>nOs#H0tGlmmg)^21ZVPwt&RWeO zvIo{sM>4S$HmaBSD!0*Jv>}(hW)vvJX2h4$)#<A~gJk8cU948g+ZjVJ(-<b>OLCDy zb;*obP0J;o7Gz7-6tm9=qe9>9L3<L1>K7r^2?%;hq!<3>NqE7sjsmPEIjtDR{4}mz zWLDt*MQMhD`pJXFY#x<NUj!`yE#J5V<H?65X{<<c2alehffdpTg`+gTDRIZ{5Hphc z_vf9WUaf2j^1Jc8Y&5AQe-+X%Oi06gSO%h&4p+`M%jX;Lyd)Vx1Q(Z$2W%mTZWxUK zvcB*vz?a_$vuL7r6Cr8dVvr(@`6<w{hrThz7pqW_mo5<zI8;!0mcFuDynYJK+4vrZ zCZxna+=TbZK9JGu#9b4+?!|BTd+3mjTu$13+BUs*<_LKlRP4GP)uHc<pb6P#rta-x z55*X=VJKq+s40aY`|~=*`{dlvlqPMv7jE1x@&hFv4vDK#EZ5mgo64<hE5fO4zNtou zrJQ;`IkgDMDxPJEp%DzDa|)2biwV`2t={L#?bVlcq~2Qd&g!ynJO)SLr#mgYvih>k zdsFpghi@j+o<PlSAy}Jqd^pc}7ItWeT2a!o+q%t+ydFS|w;H`gArQ`teVt6NM{dJb z7SB3io`eZ+p!u#}=785ir9vEiuV4NxoG?fI&GPnbGGz#g>z7Z)lOOve^~<Mh#l}!R z&G9lU_?nHK@J$*M6>i+}J4p}VB>Fyzn(6U2mZ)V;^nz*<xMg>6rwaF7va>lje8sq# zth?jL%90>+<?S9Ki<i*7L>3)eTjZjqc|_Kt`$AX9`Jgj=Fs9kOR7D6L;geYMaG*J+ zgXWR@q}Yk*!H&dDFfaB8Ln9Mo?GEgQw6DPP5aXE`BDE0u8}0yJ6}q7lW!SF6nF6It zY~oUDFC<*Ado}@9;FXdDnd?G|=5N{|Z+bl%R^#Z5UiUDn`jV-e&|+xs_>5AhqYoy| z3Jl*)Kv4b}qG)PeI~Jw$@SI!8_Q8TdoH1A%7CO=!f!K9UW2HkLRUcBrx>Il=QMyQ8 zH`DQfiMqy$O!_rMnvc#7;*Cu%Sz4Z7p_m!^N1S-{wNN(&w(vi>gN>h}cc#S;<tUER zdLlm(0|aiSvVJY?30m>_eeU{XSG8XE6#QHw6Tj~QIG#{O4deVS4t_OdW-%(uZ<y#? zOrhIAH*jb0DC)<VC~q`Ggc0Sxm6YRy02~ej?V&+v?=KL~fm311QEJErCA&=J(!)p$ zO;d#Fue4(y(dS0rJC<f($m%nL9Z&+p!lRnY$&}Ua`~;t=*IYL1b$<b*ZCE*xBikH0 z$vDWs<bD2XJe`h6k_rd=0_N~SvD-}n_8uRUQJA*Eh-LQmqrvc*5m9`7w-%lN@5AcU z!w$e?L^dYhL`^!xHv{^C9jNdF(n|?15W5#L=2zKUK(sX`L{*w8e2bwiZ=p$NH5k#b ztl&s7hAdaW-fMVm#=fmtIy^VIM(VZaAf)eT<oX;ml|MtSPmQU3S}msFW)qyBx(TC* z%LO#~JFxX0i#PPqe)5V|nQ*kW?z~0p?qI6_%Ak5h5L9PE;U37f@h^gG9)}kC+(Hgi zx2b##IZz*%5V{SK6Lr88`Ui_ERj<uUfGbt^w=j>xR@S!9Tp4=pu@U9>xYG67FB8hY z?Xu{#EeWnsdfoFDDUI}-YjX!5{sjEBhc;MTx?cNn0=Z?WiJ|)~t_gZ=TUz-f*Jymf zZ+4B*>t<iw(eFQZ+4b7?k@`ymX|4zLx{RwqcK!h~YKL@fg8QCQl|qWh5gv;|GJUl5 z0D{u5kf_V{)EB^*<zQ-{Pw5k3R3L+Q$OI)}*Ir1hK3pBo*tH>SA!Z=>!<Us<#0WcP z1;}SkDK~S>`$iE?hVg>jk&B(m&BriKtic`oaUUCcc_dBN6ZYyWIQRX+NO$nZzc&=n zvm@(2BI8Zpy#5U`X|0By`QFip$ol6{;uQa74IF47KYxv2{dxLx8Pq@=Gtjab={#uI z9lwdE{4b6v2^~IfQ;|G?1cBNQj}kT9(hnyGo7}(zJw#tLcb}5#$vc;pzdS3@OBSlz zi~T1*6H@p&_MgVHKKvc!LYHIvA7^j1`hCqoGrR%BGdKkcmg9rQtHftaCoMvF_BUWR zViTUN>Wdbz0_SYQ4-u7RFg52fM>@;_C5<U#xQ{<gVa83^Z?vJj5HSH76k9x;L*fkE zevymlKFJph^`~+bElbdX04Q4ZNvhc0#w%tN{G8CQ;Gw`IK{JxBCNgl2ByPE3+o%Bt zw?T9K`_9gYaN!UNsT2~k^d%&1ufGCeLs~txjg|slyn(HH*v!z%R3Ng`l6cuvKAqNa zf~kCz3m=L8t){<Rr-im_v_vyav>GRwusG}T6GE3X*A05@QB(PyST(gznOtM_+ILM@ zM|DoJsQ5^j$>%}9N5@cbSfaok>~9I}Ho3;@wXG)orT0v<01ug5H|lkl*|zX_VfEw3 z_4t0~g4LC&zp@?46R4q#FfDQ1WuiD9{-u4?A+{eIm*ODwNeZc&S*{S;X5NctuyB}y zC-(8|pflvCeW%DVX;@CPcs%?MSaw!E{>=Z441~zMUmW@o{8-EfQ!<TYjKAo_5lozq z$ju0iCE~c_7iGui(JgK5ptqgP{CQ#_WnhxV$ew+j27=d6OOB5<bS&j6SshPydq-J@ z=VGqa<hz9gsrl0syaHL(Bv71@j_1KU%|@PjUUO}rA_*}eyb~$RymuHngikew>C_Bj z+;!*fe>5Xfx&!C6uvX-^fuYGM@(JH0!T%YTV)S_^P~RK~A!efghKt&ynqKui1 zt@FeH!h`yy*3hp9#qM1!{r^PL|9&!yBTnewZYrNiV)!xAeZSDiAYIWQo^?MZNx>Yb zy#V!9>bX#ji44Mxrt<j^<~kqC(^6VLI}6wxuo!}ie14ghHqKPhWQpbOV8g$WPGh_o zp*bYSSOpNbx|ycPJ|oo@SmkMzxXs3VZY+l$x=a$X^FP;b*kK?~zZUW`3SxWlUEzL9 z=znSksFeR<bZmy_@u2}hOYd5ghX2`sxPEt=xjV5d9by%pX~18vPj~Pk1y9-$KHIN& z@^02^r<lrTxg2`!H=65Pdflr$W!GQ|m`}t$VHE`-o5?j<ubmIQFy7>H>UB@ZdCtI> zKn3Na;ZjX6&xYECMG`pi8lLJJ;a$Ey&z0=`KIx>FHP05T_FWalAp8*n4qwqyvg`}1 z$6t^TzE6Twg0bOQ>X|q<CHg!<OA3#Z#TN)unySJx46P+%8yk^O#(%mAFAHp-2uGx_ z0y0CHNffXAJ)5T;r{Ktu^dUg_jMX99<FhW6kgU`~U5S#xJYSjO;mEx0CiaUxL?{qo zJMY+goTm8K>o(vm%{`Sgnt#6@QZ`GxK_31GvHNXaa~qIn3N1~fHSM~CTs>s6oL-^7 z64qQ+@3hcQO|IE`Z2>0bJ0{m%^jU>#j$T)XuaWAxeK)oD;9KP!Pz*-AQLNqfULsD| z!P8ANg_HRX1*NKAuO};{vy&ghY^m4kzm|epV!={G*(UF|*Xz}n6MWNQe%Hc9vWCa0 zr)pq;y=^mx?~re}lp3B4ZIjoHA1GX$0QrC?0otE}MoQ0<_khpMxyxpm_HU+r<<Ps7 zfh6w@0@q}bVU*#d!EA0tmb>#33@2?yhhB;RyLdMdTZz%n^uGbr_I*9!CkY{tWoqKm zaS(~mj8(U^gN-j~I==}|BpZ%8xV-1V&SCX~kd&#|<PMJ!yZ@Rw{U6{o8xsBZ<X(;r zy^U5CTy=pa;bn@6>~LsqgF~~BCN$y<yxAbl7M%}W^A+=DJT`uDxH2;`1+OE>qGPWV zOalFc&=R0u!|3lrWE8r^6qCbz5#MU`Z$%oDsK#2m@C(Qsd4jw*9<y`8nM$Oz=)WL9 zGlNNJ`azP|J(1e+H~*3V<70kGoM4`O1Xp#lI%G5abAONu7~|V|N;NE+LJ2sMZ)7GG z-Lmz7OdQ>c2hPGw$3r5)&7!g07=B)^OZruzKb_P?&#(s+`u8F9_bqWHl;=gl{<r=O z;b_HO9Q5NnxC;3Rojp8B?EXG;>hHj*tBmSXCo!0~AgrKd<?_Yz7c6<O;2uXs)|`^( ze2&tRm8A~v`jzXxB@c4#Eq-ujLsHM8&4ZgCto*~*;cu{6;O1kM1^7;5xp*{r;+CUZ zJB0sp(0oStJCRbZhK_;&r;5#&W%B>MA$Rc6pzxoXlmhjE|0W*t-t<ZCV;}tAU=zT$ z1zCgt9&9#X`?IgEf$d2Dz(nDmxs^6Lb{&Vm>=8fAv3q`qyT1ZQW&G=4jr?mY_<0Ok z)$fLn>A&CR*^&b{(_b{zv&B7~nm9Z^%$W?ig0Hv#TFm*$AdD+qvrf-eYS36TRXqN< zXJ{SN$j~|mUQlO^)LA2S)<~T-QfH0mY%4k&auTFnJT~b_nRoRD&&sFDO1w`!w{~@j zwqaGtQ?s12#bb|YuNu$JmD;OoRzAPFl&Vk>d7iZrB@wNgb;t1Xopa*r@4PFnJZl&{ zVUNM*Ts5pbTO(rEtu6Cv4#%>>?|wH8cgM>6rZ}@I9FA4$Uaan`<$ZM-?z1Z#CF))# z@6@#HX$7M0tJcYKnYtINCQnltC>(<CX<C`rx5_c4?4BvB?@7}ho&WH%CCe5&W;mXH z-dnQ%d8~($_3PKJcdRb)mK1wSRy$UDCGfY<vc&7a5^@l?9aAdOv;yzS^<GDGVL7I4 zC|O_j^xEgq<kmE;giuoJG;P^h$MOYvj)hAK+)HFvVr6kjq?g+qVr6OR)6aVxt5z02 z>+r61$jMF9BCYOmtXeG`Q=E5H+(SPzr&QbqV4z<e2UIFnJ+*T6>h<?gec97L0HLcL z`3usthfAJYyMcO$P(R=6EqQL8m)@a6^uM-vrMHAfSmq@%Haxx3vF^F&9L1<35aJ^` zpN)|d8zhj?PI8KvQnHei42^eM?yZhHoU>*{-YqQIP*S>f9hek(MFX6_dgVH>3N&t* z>6pc1W-6b4UaWPjFZnZHNtyQ^<~TvC0XUvt>vf2=zULJK_%)^|3Rvu0zaDeI4Zsf~ z&FffM?0tGeiDTVL4_E_6I*3~(Wo0}%V$;gij^Z_7?9<OXJW!2mo-Qt93~Ab8G#6`u zkm*`*|1@fUtD}5nnPc_SWyLGkuPy;C1tq1B90w%93);&Z*M^#3%HjroFMPUeUFpgf z9K|G6*9IoL_3Eqm)sjXe(+Am_HVV#~PPRugC8lJI9;50tQ<7Gl@T$pdM&0WsE_JF> zf+<mRBtDjq#C3_NqmqP7LY<bRCCa)HsH2jsOQt%wsIo4F>QIt(qfE(Kj;T%48E3jG zS-GUEl8sANl&TXtO%gIgl_cb7Rg#cnP$J4CWTq-f$g!#<A;+OabV|q@R7pbGR7paP zrxK`^kP}o%Lf)uK64H+G<s@%Y<GTrURFdr`s*-FsNtI-~94dhm4j%1%lxQAgX#tly zRVf!G8lS9Nh!TxKmhz|sI%R1Q(E^;3*Nag{w8*;qQCFQ*q~>S|>Zl~?d_a{Xol8|o z()nFgl308wp}#~4xj~gAWVtFy$O<kw6yyu4Bq4vGN)qx#E(H{1r7B6tjjALet5AA< zM6H6{q)HO9T9qW^W|S&MOh}S+zNAVLvPP98WGzasCL54-sw5#_RwW7f3QE-}+Z4`v zRg#c?Rg#bmC~0Xq$+GuGRg#cfR7pZMQE9}{1PQrSl_ca3RY^j=ic)n-mg@b_RY^kr zg(^u%TIAET@mf+U)-*mmnYL2X0(dw1Nw_Jvn{oeog{B4Z51z|^8kV*<-Pgc-26zZ> z8}0^PXn_ATY!av-sfB7`dV`AI{lHfYJa6OvBmAq!zY+fh*kr&~C$wo$XK{FI72Y+t zKZ1Yv;~y!>$k?_GX>YHRJfpD*)ZK==4gW0oHwwodh+Zst4WFlL2EAs~5xw2t*R&4& zYsbHIz!D9^VcSqgu<yjc>J0m&$z+DE23~^(f_)3Hui{>be}vbnV3QQAF~_m6YZPn- z!*&8M>G-HT5bWo``(50#6zpgPD|Pp^VGX=vpoXNjk$j-Tx@fM=1}++#4fiDc>w7}e zo<Rlau<PNaqh|)*O~u7E&)&GcS1SS%T;FSY^bYOOvd@PMo0T&{=VwzwBH1@{YT8K4 zsC0e4rfW|<=zi&u>h~vU^JUwgZT;c2oFDIgi{MQ<rXxH44^AJcHY4Y0IkL?cTRxel zolTPcaUYo}S#$5X*LB~#Y=YM?TpPBC=&s>z!k<XL3P(-difMZB9>x)=3jiJ$(WL!& zH`jqCC;+<R$7F?x&Kx`L2I_CdEz@584vi_mfYd(IXrF4dx28#+nB`@)$txX}mijN; zjP?(b6CnH76;C9_QL^m~@mJiqnj?J^?faOYCPlkbm+i-ly&)kfIVDPaVwCo1d!qeK zYM+{@C0vWPNd|4G=U%PpG4mar3k$}^ym>utY?(%Tv(bLKHeJ)EPp2Q;#?s?hy0Y<S zY<4#N@C}dXZ^VcZ;Ni%TBh%B<GcqzVGc&<TyWNiHWAfz5)22<EF=NIZcifScmBsMc zRxNvymVLX1#`t@Cwl*nSvjS0UMa<i4S4^6eeaocm+b3n;Jt;ez{@$HE>GteNw`9jx z#Js(B#f%x*vu0$^nUQ_ZjO=Xsdr$U^IoUI2Wye><yuEgXrrA?8d%9*HtJ&@JcdT7Y zw`(c(_==df*RDuUw`Zi=$EMqD>2^E)wb|3h+S4=a@f9&|uU(OuX&;wqw`JNVWZLcY zcY;0BX3rdFkFSV%d+iEn&Lquh)~puIYNfvxs|K~01kD&*5%c!i74Wdq%vOupnr^nj zc3aKqR<p%wPP4{W#Js(B#mJFX%Sh{}kyd@A)k=SL>&Q{okrr!wMa<i4SIE_Qo!@x* zr!|13FcyNS(PGG+u8p0pWn)cDpPo&xsf0>iDg2H>#%g0B;A0`<SUl6mW>3!^I~_}h z5TPX+p)p|uI&L}^pnxMFZi!~p256`?UZFq`ylnp1dgN6*eEsrB<Hz+!*YzJ+@Bi=d zUt?M@1^=ZBs^*&4HBd{|{Fks}?yhrDAQ|lgkz8EasHxig_nSBW>b1?AtK^%ip_4;H zEoX;@R9VwX2XR$qVVTLxnpGKFw7Fbo&z`l}T&mjUszT#v8Lt6CHWwHEZxXo9wonIj z@k^Ijut3P>{Icb>U;XN}7F9nneZn0T?YJr!R&xnlE*m<K<?K7Now(NZcFOXmV)!7% z#h$ZW0r|paJLx*>I;r5R1D(BngMGc7foiT!NKT(PZ*bnk^kiwTKr2w&stkfP>JAs~ z65XbgCr`e3BVAmsY%R(vZEY>hvb0u80RAPG$zlYb;-@T=g;(|T7~3J(Wf`=nT842J z4Hh{iwEPVO0t!2qC*!}BH#u5w&C05*G`h!YOkQPHbo!!z{Dir2p?~QWK}19>DuO62 z9W3R4RIu49TlWPjlapU=tu#ikuhn967PY=i_3%bZOS3kd!hCJuBBrK@AB-Qs@@2!9 zKXf^57QSrJ5enCkOL3b)z#XG6F4GT4jyAx5_wcGK+9DyD=u`6z`Dtl6d9tNN37lrj zssJurYJMtPC3vgCiE^?lIXT&wUW?sT+CB)9C(14dF&P6f^;tzIx8hRbFo^bY%o4tm zs$%NtxeDzqO1^1mfQ*uFl#SssdEi=dWXPag5l^p*sE$S~>w({b(M1vB#p%<hPX!cx zRubPqB1pmyKmsaB;s<2eCH7&2fqe$Q`bw!%h|)e;KPXnMsaR9AN+^D*a#2xlO#9QV zt>PY8rk=Pv)gK8TUoKfck)<KJ-n-CMMFl$TlJ&hsd`0>rO@isfrSNxM96WtEIv(aV z71eloe1t;Lr|M6fuC%a+&Gj@!)gS7MvMkAw_CqIMi=&rN^QG`JDI{KM1#|i2$st33 zaFvauP|}Nfz~WNlA8L7-Ca<|g>PF2amy6S>>NRMvby@a^zH-UsW3g~O&8EbAjbC7N zIu%*5)fJY?$a>W}i;9Tb5P}FuWh(^0;GZ2ml>%I?Zvv`p#Ue23vr1PN@f<1sqJ9H` zw^v$Ng#&--2EwoS3(?GChN|%;Cu`|g4!EG^(HQVj02I6gj`9m2T|>~xCr{!@UZ)7X z!Ed~hQyd+StgnoSfI*+Jq)%-SQTgEZkN{(RR;P1-reuy?^@gCHFRAb7B~5u`{$-g2 zAOcU75P(Qo%1>3Y#aL49q)*j)O2<&w5rbGdS@F?g#wFWR9l_Yv$?}F%5xnYwSGa)= z`j6H#ma`?9Ino|aKV&a%KG9f<lMlehmZ5Fp%2}mZab?ip0yn8U7turb;^YP58e1lO zv1Q8OWYO@{`T*nN$^;)<-%3454MW`#Ik9C@i-V#Fb8qM?06l;2ja40|$_ZZ6=9RX$ z57LAl=AxvRW{A0^X-sdlEa{DwofYkI@<8=09>#h>dx9pVPb$9^qm`G$->Pbj{$Q6{ zFkdZ(1&l1Ot^uY`BViiCA0-b^UzMxGT8RGzu1~)aHRRFQY#k&a#DLiOqxsI_YMvgh zk6kYWA4fmrD`tJ6)M_YP?$1?PIxp55kvpI%)-iz72_;k%FviF4$c6^^N&XDd@|TYg z)mB;#hku%EnS@uWEDry8o&;gj#!gHG!JN{L(m9b55_+Y0Bg+{J<Np-?BL2_s%j5qr zXRiL~i+j~)i<IZc>!P|FR1C(Ihr?e?j=&pm#+|7i99DlZS?LB%Q*e<o(*^u7qo>CR zeTr`4BwwnmY>n|&BXNqoCK&|<5rJ3l<KZXSBJhg7yN&Vi{cdM=q$hgFcE;CVqW>s& z%r&H48rD7n&rm~Ac!s+ag=hMP*Uy<V9Djs<)$34Pe{<$U=w*BuUkr7c7BgP;K6_aE z2tG*<FIUAnz73zR2>&<;iup0<GhX!$yYyj~f{P<p+i<F*qvMpaR}@=yv_l0!vC{?L z42zL2D$zymKV7l}0O+)+eZt!+pzC1m!XRvXp<x56!G=?EsH#{670wZyDl7F2HNh7Z zTdBJqS)K@Yb{?UW`iWjv!Pr;HTKpy^qkN&t=+5peBK2P6v?~ZhzqT4Juvp|@^+JUg zhD<2;Iikd%Au(W!QBJ>+H0tmxcKpytRZ({voj^(Aue?|vs^{p<Fy@grHseWW_pZCN z)FsE$L98*R0zm6JoJDQ%;!`Ov1H&J^8_~aHrxE)r=Eev9abZ6cZcNaRm^MD-N3|RQ z%U>kiCsLxpKGj7-eN8hW{R*a735nv2jPi{jU&i>Jvt0oKy(+**d><3u&l{X)ILnb( zoSLb~-U#d?aXnRCGpaX2`Un<glPp0VsGW4oVzLMEq5QBw9%~GOsIF-Uv!@w__z-^Z z`T;x}J|nopB8f=@#0Bm~-2QSTZ0D$5$VFkq?5q;t+ZGvg;12PpONHyW(-n!m<3n|| zl44qeFHWNv9jkhycorX@SGFELeX+}M4~*zsN~DU-l`pFzbLE&Bars0>uA*{PXT;={ zvW_EsjEPI69{69RglOCd#+gDzCQUA2i~(I0hJ!>&<?s+3*b#xt)*Ot)gx_(_ss`tc zWA6c`CE}@bNyXhN?3Pis5d<4CcW<=aX(Qmq@M6MyBieQ`q!DY&71t$7ODjrCRbVFL zY@>(Pp25Krgo@k6yL_y%DFw!LJcda4#LD-o*t&}$QAcr=nxm?!$62XL%BU;4<c!JZ zQkBD^(uos;l~M~*$5})I<77htJQB-b>lP^QeM(-8NLtp#htWn9O?5OUjO?nPp=-s@ z>`hB!iddCnXGt}hQ{=41V8qSJ?8>OekWUpe%lSh)ib#jW%aUi1qby>R97D2-m184i zWBwQ{0tuYmgC|a$hz#r$aY`5?<Y|gfO?C0nab+ak#j$aO&dSzxb~Og8jEkdTF-HxN z(Nb?lN`xXHOkl){(F{gePSYD73#(Agh=gSzOk7}f%VRL2;B{PzSX(tdxyodLS5+kZ zZCBA6(@AQLVoy0Diu_{c7Ld^rMRn0qB<3|ni-^|<cnM1sCqk*15@Cs{!*uYZ@!Uq@ zTrLr0w63*P4v1wwCc?!4A?`B1RXjs*zhMsiv*&s6Mr_NWt)vXhmh%o|Q7Mp=8Fi7E zmd8hRF>{M{YQ~^NT3e+ukh(xssU9G-oCshoilAJkiBuTN4xy3e?Q3uE+uwe=y`7~s z8o`o_Ndt^>o@Ok{7pjYnfl4uSLM9?Ik7q-L5ntkCR`$>$YXK{s;#Gr71WvYv?((8o zm7lQE+dG^^r;xszr)jbz4*#7DQ(0Ci)2>>@hp5p2^^ZlT|B1-7&lbHRQKpJTF3P(> zc1$TA@;cEdw~LQNBXOweVNl{`5{Ad1v6R`2_(>6Kc;2#kBo^aZ6$vS-6{OKl-RTyI z!4xf#2odG@cr!lQjE^<rBh9;wxRiU3M3LM>B*tVK;_Kq$OVmj^jWH++<t<yjWr+B= zGBP67E<UDI5vA;XSUlOMTF9H?AbH!-OF^g?@j+yK2&q6~QBwS9gpXKo1FfwCfj|x* zBC(@_R*@r@t_mADYLxm~`r^@$QALd0E<Ri&^@3iMuffU&;gAd!jYyF-CbdOeXn17t zL86Kgop$a)>I^6`S%MVHzg&z94&y^ZC?DuTBQU&HTo?(8vHW90Lg*j-<%_kAd^CQg zf;38WN{KHc5|n{pM_e3uRTTJt3IQqZ!=`T)MSR#nsiIJiws?&oFRL<(UQ}A;3#dax z8lc43yEVc%BY@LW^o>xq6)raORW^>-5Uz2g=IIK&_Bi52*W<5McT#XxttF&WSe77n zTd~<n?g92#HAG>wxvI@8CdTlFfmT%o-eFf3U_&a}V#CjSv_^mx39X=<Ne>x&qG-Uo z%!p4T$`{qniV9Nfh>@fhLK~crR?S%%sIc@oVaeKUPSHyFV{B$_(2Q&brW~mS8*Q>7 z5GaD+s=Z3~et?)R89)ul0+%(87O({=qnk?2xeoD%b3m(Tw`3Ky%RB9l$j!xx+CZSs zLS;lQu!a@dKs%%j6eC+hf9YOnp_D&GG0}fTpeaD~X&So6UlLHF6aBzcl6!;TBT#|y zx3>?#85!V!V*t|$z9GfJQ3hg+LE6+?H7M`cDx><tVjdY(G=nQd<U1=giXey{#18O$ zyEKX#C}vRc0-0IbjN=?Uty=1j_Fd3@`>6^$m#JMvd*?bkjq^Q;7uC21qyevRl8bR- zu!md?=_{fVBve4-Y_Z*e{wmNfoNtW=Z^2f61uMpi;lBJ(bpMN-hz+#6R4K$M@T;Od zfd1j7V=s*SoQn1V@F}a5HnVzBhD%;)>Feapt1fVI9gp9lNd|P%CRJ${za_fhcTvEE zdmjyi@e!XiazZKzA>*5fGB%qCKMS5_byhl^vuXaQ8PS0o#t(r!F~}Y>7{I<V-h&=Y z@?Sew4`_C$v(pKEhGFwRD&SQ_&8S@wIZB(QLSw(TO0%nRR<*d2=ZS2*Ccac@o$8LU za2fmvU}a<hPE-}S2#)y!IKH<lepI$*fdm)YOa72Q2z^Z=3cz;sH&9ejL`!3nWmEem z+HJvR%VAXFFY(8?6JnI*Zb}ul0f`Z~6Wthh3ndY;pr!j>fiYJF0@&t&TiII#pAu~c zXrB(;?{7WQdH_x&Lf?*c7%z_}OVP&+pnmNNe;-d6mQH*3z^V3#YiKxySVKi5C%9nq z=%x)=EZFjEZ9jddXxDK+dH32QiE<ijnueF+PC(&TKn!lKmw$|1hm++ed*~mFtNQ8V zyL8IPNw|oA)DdkWP%5A5@iuN#0JW+toic#VAvI_NbRRXwCGpzW`JyhAGiA6ZHgXgQ zj^1-U{opOVCw$VSGMp*HjWQf4!*!BQ6Ja4dbLL1#iF%V|!#R>}5%)*Pab<JAh7%<F zrFz5hA(sbuBF>I6E}~C)Dbxj@F)}<F!<V6Ys>8ZF)keNcMSEX+A7*f%9f~gi_DOp> z&|c&ueJqpO>kP*vfM&!DZGaSKg>!(#8v2Yp5b{6lP8;+_1+`<RBiTatq5$ddKv5P6 zGhL7t{)6=Z;lv}<6}0mJg*DLH16rIH0r!D{NWUwWA;w*hlZ75>(#SdJMvl0GhJo@r zAS7xK+~DE|{u%1T8E8#QNid&<)XGcpM!f3IUGnhP6L79lx*Um1a5h@2HlY4={}TuP z#DPC?;7=U*69@jpf&VTJtS>2@F>B`CGw+(=oZ%_CYu4<ntl}B?jC!_n?kwk1v+i`x snSJMs=btVuD_i^g%r$GDE1CK1`jr(Wr8C#A_h?!|(tj5n|3C5kZ_EYp(EtDd literal 0 HcmV?d00001 -- 1.8.3.1 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Qemu-devel] [PATCH 8/8] virtio-gpu: add to display-vga test 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann ` (6 preceding siblings ...) 2014-09-23 13:28 ` [Qemu-devel] [PATCH 7/8] virtio-vga: add vgabios binary Gerd Hoffmann @ 2014-09-23 13:28 ` Gerd Hoffmann 7 siblings, 0 replies; 19+ messages in thread From: Gerd Hoffmann @ 2014-09-23 13:28 UTC (permalink / raw) To: qemu-devel; +Cc: Gerd Hoffmann Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- tests/Makefile | 3 +++ tests/display-vga-test.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/Makefile b/tests/Makefile index a5e3d0c..27edb2c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -125,6 +125,9 @@ check-qtest-pci-y += tests/display-vga-test$(EXESUF) gcov-files-pci-y += hw/display/vga.c gcov-files-pci-y += hw/display/cirrus_vga.c gcov-files-pci-y += hw/display/vga-pci.c +gcov-files-pci-y += hw/display/virtio-gpu.c +gcov-files-pci-y += hw/display/virtio-gpu-pci.c +gcov-files-pci-y += hw/display/virtio-vga.c check-qtest-pci-y += tests/intel-hda-test$(EXESUF) gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c index 17f5910..cd0b873 100644 --- a/tests/display-vga-test.c +++ b/tests/display-vga-test.c @@ -36,6 +36,20 @@ static void pci_multihead(void) qtest_end(); } +#ifdef CONFIG_VIRTIO_GPU +static void pci_virtio_gpu(void) +{ + qtest_start("-vga none -device virtio-gpu-pci"); + qtest_end(); +} + +static void pci_virtio_vga(void) +{ + qtest_start("-vga none -device virtio-vga"); + qtest_end(); +} +#endif + int main(int argc, char **argv) { int ret; @@ -46,6 +60,10 @@ int main(int argc, char **argv) qtest_add_func("/display/pci/stdvga", pci_stdvga); qtest_add_func("/display/pci/secondary", pci_secondary); qtest_add_func("/display/pci/multihead", pci_multihead); +#ifdef CONFIG_VIRTIO_GPU + qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu); + qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga); +#endif ret = g_test_run(); return ret; -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 19+ messages in thread
end of thread, other threads:[~2014-10-16 12:18 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-09-23 13:27 [Qemu-devel] [PATCH 0/8] add virtio-gpu Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 1/8] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann 2014-09-25 15:02 ` Gerd Hoffmann 2014-09-30 0:27 ` Dave Airlie 2014-09-30 7:54 ` Gerd Hoffmann 2014-09-30 7:55 ` Gerd Hoffmann 2014-10-03 4:38 ` Dave Airlie 2014-10-06 9:20 ` Gerd Hoffmann 2014-10-16 3:53 ` Dave Airlie 2014-10-16 12:18 ` Gerd Hoffmann 2014-10-15 10:05 ` Gerd Hoffmann 2014-10-16 3:55 ` Dave Airlie 2014-09-23 13:28 ` [Qemu-devel] [PATCH 2/8] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 3/8] virtio-gpu-pci: add virtio pci support Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 4/8] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 5/8] virtio-vga: add '-vga virtio' support Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 6/8] virtio-vga: add vgabios configuration Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 7/8] virtio-vga: add vgabios binary Gerd Hoffmann 2014-09-23 13:28 ` [Qemu-devel] [PATCH 8/8] virtio-gpu: add to display-vga test Gerd Hoffmann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).