71
71
#define MBOCHS_NAME "mbochs"
72
72
#define MBOCHS_CLASS_NAME "mbochs"
73
73
74
+ #define MBOCHS_EDID_REGION_INDEX VFIO_PCI_NUM_REGIONS
75
+ #define MBOCHS_NUM_REGIONS (MBOCHS_EDID_REGION_INDEX+1)
76
+
74
77
#define MBOCHS_CONFIG_SPACE_SIZE 0xff
75
78
#define MBOCHS_MMIO_BAR_OFFSET PAGE_SIZE
76
79
#define MBOCHS_MMIO_BAR_SIZE PAGE_SIZE
77
- #define MBOCHS_MEMORY_BAR_OFFSET (MBOCHS_MMIO_BAR_OFFSET + \
80
+ #define MBOCHS_EDID_OFFSET (MBOCHS_MMIO_BAR_OFFSET + \
78
81
MBOCHS_MMIO_BAR_SIZE)
82
+ #define MBOCHS_EDID_SIZE PAGE_SIZE
83
+ #define MBOCHS_MEMORY_BAR_OFFSET (MBOCHS_EDID_OFFSET + \
84
+ MBOCHS_EDID_SIZE)
85
+
86
+ #define MBOCHS_EDID_BLOB_OFFSET (MBOCHS_EDID_SIZE/2)
79
87
80
88
#define STORE_LE16 (addr , val ) (*(u16 *)addr = val)
81
89
#define STORE_LE32 (addr , val ) (*(u32 *)addr = val)
@@ -95,16 +103,24 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices");
95
103
static const struct mbochs_type {
96
104
const char * name ;
97
105
u32 mbytes ;
106
+ u32 max_x ;
107
+ u32 max_y ;
98
108
} mbochs_types [] = {
99
109
{
100
110
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1 ,
101
111
.mbytes = 4 ,
112
+ .max_x = 800 ,
113
+ .max_y = 600 ,
102
114
}, {
103
115
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2 ,
104
116
.mbytes = 16 ,
117
+ .max_x = 1920 ,
118
+ .max_y = 1440 ,
105
119
}, {
106
120
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3 ,
107
121
.mbytes = 64 ,
122
+ .max_x = 0 ,
123
+ .max_y = 0 ,
108
124
},
109
125
};
110
126
@@ -115,6 +131,11 @@ static struct cdev mbochs_cdev;
115
131
static struct device mbochs_dev ;
116
132
static int mbochs_used_mbytes ;
117
133
134
+ struct vfio_region_info_ext {
135
+ struct vfio_region_info base ;
136
+ struct vfio_region_info_cap_type type ;
137
+ };
138
+
118
139
struct mbochs_mode {
119
140
u32 drm_format ;
120
141
u32 bytepp ;
@@ -144,13 +165,14 @@ struct mdev_state {
144
165
u32 memory_bar_mask ;
145
166
struct mutex ops_lock ;
146
167
struct mdev_device * mdev ;
147
- struct vfio_device_info dev_info ;
148
168
149
169
const struct mbochs_type * type ;
150
170
u16 vbe [VBE_DISPI_INDEX_COUNT ];
151
171
u64 memsize ;
152
172
struct page * * pages ;
153
173
pgoff_t pagecount ;
174
+ struct vfio_region_gfx_edid edid_regs ;
175
+ u8 edid_blob [0x400 ];
154
176
155
177
struct list_head dmabufs ;
156
178
u32 active_id ;
@@ -342,10 +364,20 @@ static void handle_mmio_read(struct mdev_state *mdev_state, u16 offset,
342
364
char * buf , u32 count )
343
365
{
344
366
struct device * dev = mdev_dev (mdev_state -> mdev );
367
+ struct vfio_region_gfx_edid * edid ;
345
368
u16 reg16 = 0 ;
346
369
int index ;
347
370
348
371
switch (offset ) {
372
+ case 0x000 ... 0x3ff : /* edid block */
373
+ edid = & mdev_state -> edid_regs ;
374
+ if (edid -> link_state != VFIO_DEVICE_GFX_LINK_STATE_UP ||
375
+ offset >= edid -> edid_size ) {
376
+ memset (buf , 0 , count );
377
+ break ;
378
+ }
379
+ memcpy (buf , mdev_state -> edid_blob + offset , count );
380
+ break ;
349
381
case 0x500 ... 0x515 : /* bochs dispi interface */
350
382
if (count != 2 )
351
383
goto unhandled ;
@@ -365,6 +397,44 @@ static void handle_mmio_read(struct mdev_state *mdev_state, u16 offset,
365
397
}
366
398
}
367
399
400
+ static void handle_edid_regs (struct mdev_state * mdev_state , u16 offset ,
401
+ char * buf , u32 count , bool is_write )
402
+ {
403
+ char * regs = (void * )& mdev_state -> edid_regs ;
404
+
405
+ if (offset + count > sizeof (mdev_state -> edid_regs ))
406
+ return ;
407
+ if (count != 4 )
408
+ return ;
409
+ if (offset % 4 )
410
+ return ;
411
+
412
+ if (is_write ) {
413
+ switch (offset ) {
414
+ case offsetof(struct vfio_region_gfx_edid , link_state ):
415
+ case offsetof(struct vfio_region_gfx_edid , edid_size ):
416
+ memcpy (regs + offset , buf , count );
417
+ break ;
418
+ default :
419
+ /* read-only regs */
420
+ break ;
421
+ }
422
+ } else {
423
+ memcpy (buf , regs + offset , count );
424
+ }
425
+ }
426
+
427
+ static void handle_edid_blob (struct mdev_state * mdev_state , u16 offset ,
428
+ char * buf , u32 count , bool is_write )
429
+ {
430
+ if (offset + count > mdev_state -> edid_regs .edid_max_size )
431
+ return ;
432
+ if (is_write )
433
+ memcpy (mdev_state -> edid_blob + offset , buf , count );
434
+ else
435
+ memcpy (buf , mdev_state -> edid_blob + offset , count );
436
+ }
437
+
368
438
static ssize_t mdev_access (struct mdev_device * mdev , char * buf , size_t count ,
369
439
loff_t pos , bool is_write )
370
440
{
@@ -384,13 +454,25 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
384
454
memcpy (buf , (mdev_state -> vconfig + pos ), count );
385
455
386
456
} else if (pos >= MBOCHS_MMIO_BAR_OFFSET &&
387
- pos + count <= MBOCHS_MEMORY_BAR_OFFSET ) {
457
+ pos + count <= (MBOCHS_MMIO_BAR_OFFSET +
458
+ MBOCHS_MMIO_BAR_SIZE )) {
388
459
pos -= MBOCHS_MMIO_BAR_OFFSET ;
389
460
if (is_write )
390
461
handle_mmio_write (mdev_state , pos , buf , count );
391
462
else
392
463
handle_mmio_read (mdev_state , pos , buf , count );
393
464
465
+ } else if (pos >= MBOCHS_EDID_OFFSET &&
466
+ pos + count <= (MBOCHS_EDID_OFFSET +
467
+ MBOCHS_EDID_SIZE )) {
468
+ pos -= MBOCHS_EDID_OFFSET ;
469
+ if (pos < MBOCHS_EDID_BLOB_OFFSET ) {
470
+ handle_edid_regs (mdev_state , pos , buf , count , is_write );
471
+ } else {
472
+ pos -= MBOCHS_EDID_BLOB_OFFSET ;
473
+ handle_edid_blob (mdev_state , pos , buf , count , is_write );
474
+ }
475
+
394
476
} else if (pos >= MBOCHS_MEMORY_BAR_OFFSET &&
395
477
pos + count <=
396
478
MBOCHS_MEMORY_BAR_OFFSET + mdev_state -> memsize ) {
@@ -471,6 +553,10 @@ static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev)
471
553
mdev_state -> next_id = 1 ;
472
554
473
555
mdev_state -> type = type ;
556
+ mdev_state -> edid_regs .max_xres = type -> max_x ;
557
+ mdev_state -> edid_regs .max_yres = type -> max_y ;
558
+ mdev_state -> edid_regs .edid_offset = MBOCHS_EDID_BLOB_OFFSET ;
559
+ mdev_state -> edid_regs .edid_max_size = sizeof (mdev_state -> edid_blob );
474
560
mbochs_create_config_space (mdev_state );
475
561
mbochs_reset (mdev );
476
562
@@ -932,16 +1018,16 @@ static int mbochs_dmabuf_export(struct mbochs_dmabuf *dmabuf)
932
1018
}
933
1019
934
1020
static int mbochs_get_region_info (struct mdev_device * mdev ,
935
- struct vfio_region_info * region_info ,
936
- u16 * cap_type_id , void * * cap_type )
1021
+ struct vfio_region_info_ext * ext )
937
1022
{
1023
+ struct vfio_region_info * region_info = & ext -> base ;
938
1024
struct mdev_state * mdev_state ;
939
1025
940
1026
mdev_state = mdev_get_drvdata (mdev );
941
1027
if (!mdev_state )
942
1028
return - EINVAL ;
943
1029
944
- if (region_info -> index >= VFIO_PCI_NUM_REGIONS )
1030
+ if (region_info -> index >= MBOCHS_NUM_REGIONS )
945
1031
return - EINVAL ;
946
1032
947
1033
switch (region_info -> index ) {
@@ -964,6 +1050,20 @@ static int mbochs_get_region_info(struct mdev_device *mdev,
964
1050
region_info -> flags = (VFIO_REGION_INFO_FLAG_READ |
965
1051
VFIO_REGION_INFO_FLAG_WRITE );
966
1052
break ;
1053
+ case MBOCHS_EDID_REGION_INDEX :
1054
+ ext -> base .argsz = sizeof (* ext );
1055
+ ext -> base .offset = MBOCHS_EDID_OFFSET ;
1056
+ ext -> base .size = MBOCHS_EDID_SIZE ;
1057
+ ext -> base .flags = (VFIO_REGION_INFO_FLAG_READ |
1058
+ VFIO_REGION_INFO_FLAG_WRITE |
1059
+ VFIO_REGION_INFO_FLAG_CAPS );
1060
+ ext -> base .cap_offset = offsetof(typeof (* ext ), type );
1061
+ ext -> type .header .id = VFIO_REGION_INFO_CAP_TYPE ;
1062
+ ext -> type .header .version = 1 ;
1063
+ ext -> type .header .next = 0 ;
1064
+ ext -> type .type = VFIO_REGION_TYPE_GFX ;
1065
+ ext -> type .subtype = VFIO_REGION_SUBTYPE_GFX_EDID ;
1066
+ break ;
967
1067
default :
968
1068
region_info -> size = 0 ;
969
1069
region_info -> offset = 0 ;
@@ -984,7 +1084,7 @@ static int mbochs_get_device_info(struct mdev_device *mdev,
984
1084
struct vfio_device_info * dev_info )
985
1085
{
986
1086
dev_info -> flags = VFIO_DEVICE_FLAGS_PCI ;
987
- dev_info -> num_regions = VFIO_PCI_NUM_REGIONS ;
1087
+ dev_info -> num_regions = MBOCHS_NUM_REGIONS ;
988
1088
dev_info -> num_irqs = VFIO_PCI_NUM_IRQS ;
989
1089
return 0 ;
990
1090
}
@@ -1084,7 +1184,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
1084
1184
unsigned long arg )
1085
1185
{
1086
1186
int ret = 0 ;
1087
- unsigned long minsz ;
1187
+ unsigned long minsz , outsz ;
1088
1188
struct mdev_state * mdev_state ;
1089
1189
1090
1190
mdev_state = mdev_get_drvdata (mdev );
@@ -1106,33 +1206,31 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
1106
1206
if (ret )
1107
1207
return ret ;
1108
1208
1109
- memcpy (& mdev_state -> dev_info , & info , sizeof (info ));
1110
-
1111
1209
if (copy_to_user ((void __user * )arg , & info , minsz ))
1112
1210
return - EFAULT ;
1113
1211
1114
1212
return 0 ;
1115
1213
}
1116
1214
case VFIO_DEVICE_GET_REGION_INFO :
1117
1215
{
1118
- struct vfio_region_info info ;
1119
- u16 cap_type_id = 0 ;
1120
- void * cap_type = NULL ;
1216
+ struct vfio_region_info_ext info ;
1121
1217
1122
- minsz = offsetofend (struct vfio_region_info , offset );
1218
+ minsz = offsetofend (typeof ( info ), base . offset );
1123
1219
1124
1220
if (copy_from_user (& info , (void __user * )arg , minsz ))
1125
1221
return - EFAULT ;
1126
1222
1127
- if (info .argsz < minsz )
1223
+ outsz = info .base .argsz ;
1224
+ if (outsz < minsz )
1225
+ return - EINVAL ;
1226
+ if (outsz > sizeof (info ))
1128
1227
return - EINVAL ;
1129
1228
1130
- ret = mbochs_get_region_info (mdev , & info , & cap_type_id ,
1131
- & cap_type );
1229
+ ret = mbochs_get_region_info (mdev , & info );
1132
1230
if (ret )
1133
1231
return ret ;
1134
1232
1135
- if (copy_to_user ((void __user * )arg , & info , minsz ))
1233
+ if (copy_to_user ((void __user * )arg , & info , outsz ))
1136
1234
return - EFAULT ;
1137
1235
1138
1236
return 0 ;
@@ -1148,7 +1246,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
1148
1246
return - EFAULT ;
1149
1247
1150
1248
if ((info .argsz < minsz ) ||
1151
- (info .index >= mdev_state -> dev_info . num_irqs ))
1249
+ (info .index >= VFIO_PCI_NUM_IRQS ))
1152
1250
return - EINVAL ;
1153
1251
1154
1252
ret = mbochs_get_irq_info (mdev , & info );
0 commit comments