Signed-off-by: Gerd Hoffmann <[email protected]>
---
 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

Reply via email to