summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/qemu/qemu-0.13.0/vmware-vga-fifo-rewind.patch
blob: 867e54ba115336db30aeb6b7192fc693361c6936 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
commit 4dedc07ffbbc66002e0fd2b97d5516fe6aca5eea
Author: Andrzej Zaborowski <balrog@zabor.org>
Date:   Fri Sep 10 02:23:31 2010 +0200

    vmware_vga: Add checks to deal with non-atomic fifo writes.
    
    Janne Huttunen noticed that the FIFO end pointer is updated by the
    guest after writing each word to the FIFO, at least the X.org driver
    which is open does this.  This means that there's no way for the
    host to know if the guest is in the middle a write operation.  Qemu
    thus needs to read the beginning of the command up to when it's able
    to tell how many words are expected for the given command.  It will
    abort reading and rewind the FIFO if there aren't enough words yet,
    this should be relatively rare but it is suspected to have been the
    cause of the occasional FIFO overrun that killed the display.

Index: qemu-0.13.0/hw/vmware_vga.c
===================================================================
--- qemu-0.13.0.orig/hw/vmware_vga.c	2011-01-15 18:06:06.000000000 +0800
+++ qemu-0.13.0/hw/vmware_vga.c	2011-01-15 18:17:04.000000000 +0800
@@ -521,27 +521,37 @@
 
 static uint32_t last_cmd;
 
-static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s)
+static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
 {
+    int num;
     if (!s->config || !s->enable)
-        return 1;
-    return (s->cmd->next_cmd == s->cmd->stop);
+        return 0;
+    num = CMD(next_cmd) - CMD(stop);
+    if (num < 0)
+        num += CMD(max) - CMD(min);
+    return num >> 2;
 }
 
 static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
 {
-    int offset = CMD(stop);
+    uint32_t cmd = s->fifo[CMD(stop) >> 2];
 
+    /* If parameter is not available in FIFO, return 0 rather than random
+     * value. Also update the stop as missing parameter will be inserted
+     * soonly, else it will be treated as new command next time.
+     * With rewinding in vmsvga_fifo_run, this unlikely happen.
+     */
     if (unlikely(s->cmd->next_cmd == s->cmd->stop)) {
         fprintf(stderr, "%s: FIFO empty during CMD %i\n",
                         __FUNCTION__, last_cmd);
-        return 0x00000000;
+        cmd = 0;
     }
 
-    s->cmd->stop = cpu_to_le32(offset + 4);
-    if (offset + 4 >= CMD(max))
+    s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
+    if (CMD(stop) >= CMD(max))
         s->cmd->stop = s->cmd->min;
-    return s->fifo[offset >> 2];
+
+    return cmd;
 }
 
 static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
@@ -552,13 +562,23 @@
 static void vmsvga_fifo_run(struct vmsvga_state_s *s)
 {
     uint32_t colour;
-    int args = 0;
+    int args, len;
     int x, y, dx, dy, width, height;
     struct vmsvga_cursor_definition_s cursor;
-    while (!vmsvga_fifo_empty(s))
+    uint32_t cmd_start;
+
+    len = vmsvga_fifo_length(s);
+    while (len > 0) {
+        /* May need to go back to the start of the command if incomplete */
+        cmd_start = s->cmd->stop;
+
         switch (last_cmd = vmsvga_fifo_read(s)) {
         case SVGA_CMD_UPDATE:
         case SVGA_CMD_UPDATE_VERBOSE:
+            len -= 5;
+            if (len <0)
+                goto rewind;
+
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
             width = vmsvga_fifo_read(s);
@@ -567,6 +587,10 @@
             break;
 
         case SVGA_CMD_RECT_FILL:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
             colour = vmsvga_fifo_read(s);
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
@@ -576,10 +600,15 @@
             vmsvga_fill_rect(s, colour, x, y, width, height);
             break;
 #else
+            args = 0;
             goto badcmd;
 #endif
 
         case SVGA_CMD_RECT_COPY:
+            len -= 7;
+            if (len < 0)
+                goto rewind;
+
             x = vmsvga_fifo_read(s);
             y = vmsvga_fifo_read(s);
             dx = vmsvga_fifo_read(s);
@@ -590,10 +619,15 @@
             vmsvga_copy_rect(s, x, y, dx, dy, width, height);
             break;
 #else
+            args = 0;
             goto badcmd;
 #endif
 
         case SVGA_CMD_DEFINE_CURSOR:
+            len -= 8;
+            if (len < 0)
+                goto rewind;
+
             cursor.id = vmsvga_fifo_read(s);
             cursor.hot_x = vmsvga_fifo_read(s);
             cursor.hot_y = vmsvga_fifo_read(s);
@@ -602,11 +636,14 @@
             vmsvga_fifo_read(s);
             cursor.bpp = vmsvga_fifo_read(s);
 
+            args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
 	    if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
-		SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
-		    args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
+		SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image)
 		    goto badcmd;
-	    }
+
+            len -= args;
+            if (len < 0)
+                goto rewind;
 
             for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
                 cursor.mask[args] = vmsvga_fifo_read_raw(s);
@@ -625,6 +662,10 @@
          * for so we can avoid FIFO desync if driver uses them illegally.
          */
         case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+            len -= 6;
+            if (len < 0)
+                goto rewind;
+
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
@@ -639,6 +680,10 @@
             args = 7;
             goto badcmd;
         case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+            len -= 4;
+            if (len < 0)
+                goto rewind;
+
             vmsvga_fifo_read(s);
             vmsvga_fifo_read(s);
             args = 7 + (vmsvga_fifo_read(s) >> 2);
@@ -659,14 +704,22 @@
             break; /* Nop */
 
         default:
+            args = 0;
         badcmd:
+            len -= args;
+            if (len < 0)
+                goto rewind;
             while (args --)
                 vmsvga_fifo_read(s);
             printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
                             __FUNCTION__, last_cmd);
             break;
+        rewind:
+            s->cmd->stop = cmd_start;
+            break;
         }
 
+    }
     s->syncing = 0;
 }