Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxxxxx> --- samples/vfio-mdev/mbochs.c | 54 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index 2535c3677c..6331871ff5 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -95,16 +95,24 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices"); static const struct mbochs_type { const char *name; u32 mbytes; + u32 max_x; + u32 max_y; } mbochs_types[] = { { .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, .mbytes = 4, + .max_x = 800, + .max_y = 600, }, { .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, .mbytes = 16, + .max_x = 1920, + .max_y = 1440, }, { .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, .mbytes = 64, + .max_x = 0, + .max_y = 0, }, }; @@ -151,6 +159,7 @@ struct mdev_state { u64 memsize; struct page **pages; pgoff_t pagecount; + u8 edid[512]; struct list_head dmabufs; u32 active_id; @@ -346,6 +355,11 @@ static void handle_mmio_read(struct mdev_state *mdev_state, u16 offset, int index; switch (offset) { + case 0x000 ... 0x3ff: /* edid block */ + if (offset + count > sizeof(mdev_state->edid)) + goto unhandled; + memcpy(buf, mdev_state->edid + offset, count); + break; case 0x500 ... 0x515: /* bochs dispi interface */ if (count != 2) goto unhandled; @@ -983,9 +997,13 @@ static int mbochs_get_irq_info(struct mdev_device *mdev, static int mbochs_get_device_info(struct mdev_device *mdev, struct vfio_device_info *dev_info) { + struct mdev_state *mdev_state = mdev_get_drvdata(mdev); + dev_info->flags = VFIO_DEVICE_FLAGS_PCI; dev_info->num_regions = VFIO_PCI_NUM_REGIONS; dev_info->num_irqs = VFIO_PCI_NUM_IRQS; + dev_info->edid_max_x = mdev_state->type->max_x; + dev_info->edid_max_y = mdev_state->type->max_y; return 0; } @@ -1084,7 +1102,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, unsigned long arg) { int ret = 0; - unsigned long minsz; + unsigned long minsz, outsz; struct mdev_state *mdev_state; mdev_state = mdev_get_drvdata(mdev); @@ -1095,6 +1113,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, struct vfio_device_info info; minsz = offsetofend(struct vfio_device_info, num_irqs); + outsz = offsetofend(struct vfio_device_info, edid_max_y); if (copy_from_user(&info, (void __user *)arg, minsz)) return -EFAULT; @@ -1108,7 +1127,9 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, memcpy(&mdev_state->dev_info, &info, sizeof(info)); - if (copy_to_user((void __user *)arg, &info, minsz)) + if (outsz > info.argsz) + outsz = info.argsz; + if (copy_to_user((void __user *)arg, &info, outsz)) return -EFAULT; return 0; @@ -1194,6 +1215,35 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd, return mbochs_get_gfx_dmabuf(mdev, dmabuf_id); } + case VFIO_DEVICE_SET_GFX_EDID: + { + struct vfio_device_set_gfx_edid *edid; + + edid = kmalloc(sizeof(*edid), GFP_KERNEL); + + minsz = offsetofend(struct vfio_device_set_gfx_edid, + edid_blob); + + if (copy_from_user(edid, (void __user *)arg, minsz)) { + kfree(edid); + return -EFAULT; + } + + if (edid->argsz < minsz || + edid->edid_size > sizeof(mdev_state->edid)) { + kfree(edid); + return -EINVAL; + } + + memset(mdev_state->edid, 0, sizeof(mdev_state->edid)); + if (edid->link_state == VFIO_DEVICE_GFX_LINK_STATE_UP) { + memcpy(mdev_state->edid, edid->edid_blob, edid->edid_size); + } + kfree(edid); + + return 0; + } + case VFIO_DEVICE_SET_IRQS: return -EINVAL; -- 2.9.3