Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


From 294306ec5026ea691a4f1380598114688b061c99 Mon Sep 17 00:00:00 2001
[palacios.git] / palacios / src / devices / cirrus_gfx_card.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2009, Robert Deloatch <rtdeloatch@gmail.com>
11  * Copyright (c) 2009, Steven Jaconette <stevenjaconette2007@u.northwestern.edu> 
12  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Robdert Deloatch <rtdeloatch@gmail.com>
16  *         Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22
23 #include <devices/cirrus_gfx_card.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_emulator.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vm_guest_mem.h>
28 #include <palacios/vmm_decoder.h>
29 #include <palacios/vmm_paging.h>
30 #include <palacios/vmm_instr_emulator.h>
31 #include <palacios/vm_guest_mem.h>
32 #include <palacios/vmm_socket.h>
33 #include <palacios/vmm_host_events.h>
34 #include <devices/pci.h>
35 #include <devices/pci_types.h>
36
37 #include "network_console.h"
38
39
40
41 /* #ifndef DEBUG_CIRRUS_GFX_CARD
42 #undef PrintDebug
43 #define PrintDebug(fmt, args...)
44 #endif */
45
46
47 #define START_ADDR 0xA0000
48 #define END_ADDR 0xC0000
49
50 #define SIZE_OF_REGION (END_ADDR - START_ADDR)
51
52 #define PASSTHROUGH 1
53 #define PORT_OFFSET 0x3B0
54
55 struct video_internal {
56     addr_t video_memory_pa;
57     uint8_t * video_memory;
58     
59     struct vm_device * pci_bus;
60     struct pci_device * pci_dev;
61
62     int client_fd;
63
64     uint_t screen_bottom;
65     uint_t ports[44];
66     uint8_t reg_3C4[256];
67     uint8_t reg_3CE[256];
68     uint16_t start_addr_offset;
69     uint16_t old_start_addr_offset;
70     uint16_t cursor_addr;
71     uint8_t reg_3D5[25];
72     
73 };
74
75 void video_do_in(uint16_t port, void * src, uint_t length){
76 #if PASSTHROUGH
77     uint_t i;
78     switch (length) {
79         case 1:
80             ((uint8_t *)src)[0] = v3_inb(port);
81             break;
82         case 2:
83             ((uint16_t *)src)[0] = v3_inw(port);
84             break;
85         case 4:
86             ((uint32_t *)src)[0] = v3_indw(port);
87             break;
88         default:
89             for (i = 0; i < length; i++) { 
90                 ((uint8_t *)src)[i] = v3_inb(port);
91             }
92     }
93 #endif
94 }
95
96 void video_do_out(uint16_t port, void * src, uint_t length){
97 #if PASSTHROUGH
98     uint_t i;
99     switch (length) {
100         case 1:
101             v3_outb(port,((uint8_t *)src)[0]);
102             break;
103         case 2:
104             v3_outw(port,((uint16_t *)src)[0]);
105             break;
106         case 4:
107             v3_outdw(port,((uint32_t *)src)[0]);
108             break;
109         default:
110             for (i = 0; i < length; i++) { 
111                 v3_outb(port, ((uint8_t *)src)[i]);
112             }
113     }
114 #endif
115 }
116
117 static int video_write_mem(addr_t guest_addr, void * dest, uint_t length, void * priv_data) {
118     struct vm_device * dev = (struct vm_device *)priv_data;
119     struct video_internal * data = (struct video_internal *)dev->private_data;
120     addr_t write_offset = guest_addr - START_ADDR;
121     uint_t difference = 0x18000;
122     int i = 0;
123
124
125     PrintDebug("\n\nInside Video Write Memory.\n\n");
126     PrintDebug("Guest address: %p length = %d\n", (void *)guest_addr, length);
127
128     PrintDebug("Write offset: 0x%x\n", (uint_t)write_offset);
129     PrintDebug("Video_Memory: ");
130
131     for (i = 0; i < length; i += 2) {
132         PrintDebug("%c", ((char *)(V3_VAddr((void *)guest_addr)))[i]);
133     }
134
135 #if PASSTHROUGH
136     memcpy(data->video_memory + write_offset, V3_VAddr((void*)guest_addr), length);
137 #endif
138
139
140
141     if (send_update(data->client_fd, data->video_memory + difference, write_offset-difference, data->start_addr_offset, length) == -1) {
142         PrintError("Error sending update to client\n");
143         return -1;
144     }
145
146     PrintDebug(" Done.\n");
147     return length;
148 }
149
150 static int video_read_port(uint16_t port, void * dest, uint_t length, struct vm_device * dev) {
151     //PrintDebug("Video: Read port 0x%x\n",port);
152     video_do_in(port, dest, length);
153     return length;
154 }
155
156 static int video_read_port_generic(uint16_t port, void * dest, uint_t length, struct vm_device * dev) {
157     memset(dest, 0, length);
158     video_do_in(port, dest, length);
159     return length;
160 }
161
162
163 static int video_write_port(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
164     /*
165       PrintDebug("Video: write port 0x%x...Wrote: ", port);
166       uint_t i;
167       for(i = 0; i < length; i++){
168       PrintDebug("%x", ((uint8_t*)src)[i]);
169       }
170       PrintDebug("...Done\n"); */
171     video_do_out(port, src, length);
172     return length;
173 }
174
175 static int video_write_port_store(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
176     /*
177       PrintDebug("Entering video_write_port_store...port 0x%x\n", port);
178       uint_t i;
179       for(i = 0; i < length; i++){
180       PrintDebug("%x", ((uint8_t*)src)[i]);
181       }
182       PrintDebug("...Done\n"); 
183     */
184     struct video_internal * video_state = (struct video_internal *)dev->private_data;
185
186     video_state->ports[port - PORT_OFFSET] = 0;
187     memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
188     video_do_out(port, src, length);
189
190     return length;
191 }
192
193 static int video_write_port_3D5(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
194     struct video_internal * video_state = (struct video_internal *)dev->private_data;
195     uint8_t new_start = 0;
196     uint_t index = 0;
197
198     PrintDebug("Video: write port 0x%x...Wrote: ", port);
199     {
200         uint_t i = 0;
201         for (i = 0; i < length; i++){
202             PrintDebug("%x", ((uint8_t*)src)[i]);
203         }
204         PrintDebug("...Done\n");
205     }
206
207     video_state->ports[port - PORT_OFFSET] = 0;
208
209     memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
210
211     memcpy(&(video_state->reg_3D5[index]), src, length);
212
213     index = video_state->ports[port - 1 - PORT_OFFSET];
214
215     // JRL: Add length check
216     new_start = *((uint8_t *)src);
217
218
219     switch (index) {
220         case 0x0c:
221             video_state->old_start_addr_offset = video_state->start_addr_offset;
222
223             video_state->start_addr_offset = (new_start << 8);
224
225             break;
226         case 0x0d: {
227             int diff = 0;
228
229             video_state->start_addr_offset += new_start;
230
231             diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
232             diff /= 80;
233
234             PrintDebug("Scroll lines = %d\n", diff);
235
236             send_scroll(video_state->client_fd, diff, video_state->video_memory);
237
238             break;
239         }
240         case 0x0E:
241             video_state->cursor_addr = new_start << 8;
242
243             break;
244         case 0x0F: {
245             uint_t x = 0;
246             uint_t y = 0;
247
248             video_state->cursor_addr += new_start;
249            
250             x = ((video_state->cursor_addr) % 80) + 1;
251             y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
252             
253             PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
254             
255             send_cursor_update(video_state->client_fd, x, y);
256             break;
257         }
258         default:
259             break;
260     }
261
262     video_do_out(port, src, length);
263
264     return length;
265 }
266
267
268 static int video_write_port_3C5(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
269     struct video_internal * video_state = (struct video_internal *)dev->private_data;
270     uint_t index = 0;
271
272
273     PrintDebug("Entering write_port_3C5....port 0x%x\n", port);
274     {
275         uint_t i = 0;
276         for(i = 0; i < length; i++){
277             PrintDebug("%x", ((uint8_t*)src)[i]);
278         }
279         PrintDebug("...Done\n");
280     }
281
282     video_state->ports[port - PORT_OFFSET] = 0;
283     memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
284
285     index = video_state->ports[port - 1 - PORT_OFFSET];
286
287     memcpy(&(video_state->reg_3C4[index]), src, length);
288     video_do_out(port, src, length);
289
290     return length;
291 }
292
293 static int video_write_port_3CF(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
294     struct video_internal * video_state = (struct video_internal *)dev->private_data;
295
296     PrintDebug("Entering write_port_3CF....port 0x%x\n", port);
297
298     {
299         uint_t i = 0;
300         for(i = 0; i < length; i++){
301             PrintDebug("%x", ((uint8_t*)src)[i]);
302         }
303         PrintDebug("...Done\n");
304     }
305
306     video_state->ports[port - PORT_OFFSET] = 0;
307     memcpy(video_state->ports + (port - PORT_OFFSET), src, length); 
308
309     uint_t index = video_state->ports[port - 1 - PORT_OFFSET];
310     memcpy(&(video_state->reg_3CE[index]), src, length);
311     video_do_out(port, src, length);
312     return length;
313 }
314
315 static int video_write_port_3D4(uint16_t port, void * src, uint_t length, struct vm_device * dev){
316     struct video_internal * video_state = (struct video_internal *) dev -> private_data;
317
318 #if 1
319     if (length == 1) {
320
321         video_state->ports[port - PORT_OFFSET] = 0;
322         memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
323
324     } else if (length == 2) {
325         uint16_t new_start = *((uint16_t *)src);
326         uint16_t cursor_start = *((uint16_t *)src);;
327
328         //Updating the cursor
329         if ((cursor_start & 0x00FF) == 0x000E) {
330
331             cursor_start = (cursor_start & 0xFF00);
332             video_state->cursor_addr = cursor_start;
333
334         } else if ((cursor_start & 0x00FF) == 0x000F) {
335             uint_t x = 0;
336             uint_t y = 0;
337
338             video_state->cursor_addr += ((cursor_start >> 8) & 0x00FF);
339
340             x = ((video_state->cursor_addr) % 80) + 1;
341             y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
342
343             PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
344
345             send_cursor_update(video_state->client_fd, x, y);
346         }
347
348         //Checking to see if scrolling is needed
349         if ((new_start & 0x00FF) == 0x000C) {
350
351             video_state->old_start_addr_offset = video_state->start_addr_offset;
352             new_start = (new_start & 0xFF00);
353             video_state->start_addr_offset = new_start;
354
355         } else if ((new_start & 0x00FF) == 0x000D) {
356             int diff = 0;
357
358             video_state->start_addr_offset += ((new_start >> 8) & 0x00FF);
359
360             diff =  video_state->start_addr_offset - video_state->old_start_addr_offset;
361             diff /= 80;
362
363             PrintDebug("Scroll lines = %d\n", diff);
364
365             send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
366         }
367     } else {
368         // JRL ??
369         return -1;
370     }
371 #endif 
372     video_do_out(port, src, length);
373     return length;
374 }
375
376 static int video_write_mem_region(addr_t guest_addr, void * src, uint_t length, void * priv_data) {;
377     PrintDebug("Video write mem region guest_addr: 0x%p, src: 0x%p, length: %d, Value?= %x\n", (void *)guest_addr, src, length, *((uint32_t *)V3_VAddr((void *)guest_addr)));
378     return length;
379 }
380
381 static int video_read_mem_region(addr_t guest_addr, void * dest, uint_t length, void * priv_data){
382     PrintDebug("Video:  Within video_read_mem_region\n");
383     return length;
384 }
385
386 static int video_write_io_region(addr_t guest_addr, void * src, uint_t length, void * priv_data){
387     PrintDebug("Video:  Within video_write_io_region\n");
388     return length;
389 }
390
391 static int video_read_io_region(addr_t guest_addr, void * dest, uint_t length, void * priv_data){
392     PrintDebug("Video:  Within video_read_io_region\n");
393     return length;
394 }
395
396 static int cirrus_gfx_card_free(struct vm_device * dev) {
397     v3_unhook_mem(dev->vm, START_ADDR);
398     return 0;
399 }
400
401 static int cirrus_gfx_card_reset_device(struct vm_device * dev) {
402     PrintDebug("Video: reset device\n");
403     return 0;
404 }
405
406 static int cirrus_gfx_card_start_device(struct vm_device * dev) {
407     PrintDebug("Video: start device\n");
408     return 0;
409 }
410
411 static int cirrus_gfx_card_stop_device(struct vm_device * dev) {
412     PrintDebug("Video: stop device\n");
413     return 0;
414 }
415
416 static struct v3_device_ops dev_ops = {
417     .free = cirrus_gfx_card_free,
418     .reset = cirrus_gfx_card_reset_device,
419     .start = cirrus_gfx_card_start_device,
420     .stop = cirrus_gfx_card_stop_device,
421 };
422
423 static int cirrus_gfx_card_init(struct guest_info * vm, void * cfg_data){
424     struct video_internal * video_state = (struct video_internal *)V3_Malloc(sizeof(struct video_internal));
425     struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
426     struct vm_device * dev = v3_allocate_device("TEXT_GFX_CARD", &dev_ops, video_state);
427
428     if (v3_attach_device(vm, dev) == -1) {
429         PrintError("Could not attach device %s\n", "TEXT_GFX_CARD");
430         return -1;
431     }
432
433     PrintDebug("video: init_device\n");
434     PrintDebug("Num Pages=%d\n", SIZE_OF_REGION / 4096);
435
436     video_state->video_memory_pa = (addr_t)V3_AllocPages(SIZE_OF_REGION / 4096);
437     video_state->video_memory = V3_VAddr((void *)video_state->video_memory_pa);
438
439     memset(video_state->video_memory, 0, SIZE_OF_REGION);
440
441
442     v3_dev_hook_io(dev, 0x3b0, &video_read_port, &video_write_port);
443     v3_dev_hook_io(dev, 0x3b1, &video_read_port, &video_write_port);
444     v3_dev_hook_io(dev, 0x3b2, &video_read_port, &video_write_port);
445     v3_dev_hook_io(dev, 0x3b3, &video_read_port, &video_write_port);
446     v3_dev_hook_io(dev, 0x3b4, &video_read_port, &video_write_port);
447     v3_dev_hook_io(dev, 0x3b5, &video_read_port, &video_write_port);
448     v3_dev_hook_io(dev, 0x3b6, &video_read_port, &video_write_port);
449     v3_dev_hook_io(dev, 0x3b7, &video_read_port, &video_write_port);
450     v3_dev_hook_io(dev, 0x3b8, &video_read_port, &video_write_port);
451     v3_dev_hook_io(dev, 0x3b9, &video_read_port, &video_write_port);
452     v3_dev_hook_io(dev, 0x3ba, &video_read_port, &video_write_port);
453     v3_dev_hook_io(dev, 0x3bb, &video_read_port, &video_write_port);
454     v3_dev_hook_io(dev, 0x3c0, &video_read_port, &video_write_port_store);
455     v3_dev_hook_io(dev, 0x3c1, &video_read_port, &video_write_port);
456     v3_dev_hook_io(dev, 0x3c2, &video_read_port, &video_write_port_store);
457     v3_dev_hook_io(dev, 0x3c3, &video_read_port, &video_write_port);
458     v3_dev_hook_io(dev, 0x3c4, &video_read_port, &video_write_port_store);
459     v3_dev_hook_io(dev, 0x3c5, &video_read_port, &video_write_port_3C5);
460     v3_dev_hook_io(dev, 0x3c6, &video_read_port, &video_write_port_store);
461     v3_dev_hook_io(dev, 0x3c7, &video_read_port, &video_write_port);
462     v3_dev_hook_io(dev, 0x3c8, &video_read_port, &video_write_port_store);
463     v3_dev_hook_io(dev, 0x3c9, &video_read_port, &video_write_port_store);
464     v3_dev_hook_io(dev, 0x3ca, &video_read_port, &video_write_port);
465     v3_dev_hook_io(dev, 0x3cb, &video_read_port, &video_write_port);
466     v3_dev_hook_io(dev, 0x3cc, &video_read_port, &video_write_port);
467     v3_dev_hook_io(dev, 0x3cd, &video_read_port, &video_write_port);
468     v3_dev_hook_io(dev, 0x3ce, &video_read_port, &video_write_port_store);
469     v3_dev_hook_io(dev, 0x3cf, &video_read_port, &video_write_port_3CF);
470     v3_dev_hook_io(dev, 0x3d0, &video_read_port, &video_write_port);
471     v3_dev_hook_io(dev, 0x3d1, &video_read_port, &video_write_port);
472     v3_dev_hook_io(dev, 0x3d2, &video_read_port, &video_write_port);
473     v3_dev_hook_io(dev, 0x3d3, &video_read_port, &video_write_port);
474     v3_dev_hook_io(dev, 0x3d4, &video_read_port, &video_write_port_3D4);
475     v3_dev_hook_io(dev, 0x3d5, &video_read_port, &video_write_port_3D5);
476     v3_dev_hook_io(dev, 0x3d6, &video_read_port, &video_write_port);
477     v3_dev_hook_io(dev, 0x3d7, &video_read_port, &video_write_port);
478     v3_dev_hook_io(dev, 0x3d8, &video_read_port, &video_write_port);
479     v3_dev_hook_io(dev, 0x3d9, &video_read_port, &video_write_port);
480     v3_dev_hook_io(dev, 0x3da, &video_read_port_generic, &video_write_port);
481     v3_dev_hook_io(dev, 0x3db, &video_read_port, &video_write_port);
482     v3_dev_hook_io(dev, 0x3dc, &video_read_port, &video_write_port);
483     v3_dev_hook_io(dev, 0x3dd, &video_read_port, &video_write_port);
484     v3_dev_hook_io(dev, 0x3de, &video_read_port, &video_write_port);
485     v3_dev_hook_io(dev, 0x3df, &video_read_port, &video_write_port);
486
487
488     PrintDebug("PA of array: %p\n", (void *)video_state->video_memory_pa);
489
490
491 #if PASSTHROUGH
492     if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, START_ADDR, &video_write_mem, dev) == -1){
493         PrintDebug("\n\nVideo Hook failed.\n\n");
494     }
495 #else
496     if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, video_memory_pa, &video_write_mem, dev) == -1){
497         PrintDebug("\n\nVideo Hook failed.\n\n");
498     }
499 #endif
500
501     PrintDebug("Video: Getting client connection\n");
502
503     video_state->client_fd = get_client_connection(vm);
504
505     PrintDebug("Video: Client connection established\n");
506
507     video_state->screen_bottom = 25;
508
509     video_state->pci_bus = pci_bus;
510
511     if (video_state->pci_bus == NULL) {
512         PrintError("Could not find PCI device\n");
513         return -1;
514     } else {
515         struct v3_pci_bar bars[6];
516         struct pci_device * pci_dev = NULL;
517
518         int i;
519         for (i = 0; i < 6; i++) {
520             bars[i].type = PCI_BAR_NONE;
521         }
522
523         bars[0].type = PCI_BAR_MEM32;
524         bars[0].num_pages = 8192;
525         bars[0].default_base_addr = 0xf0000000;
526
527         bars[0].mem_read = video_read_mem_region;
528         bars[0].mem_write = video_write_mem_region;
529
530         bars[1].type = PCI_BAR_MEM32;
531         bars[1].num_pages = 1;
532         bars[1].default_base_addr = 0xf2000000;
533     
534         bars[1].mem_read = video_read_io_region;
535         bars[1].mem_write = video_write_io_region;
536         //-1 Means autoassign
537         //                                                     Not sure if STD
538         pci_dev = v3_pci_register_device(video_state->pci_bus, PCI_STD_DEVICE, 0,
539                                          //or0  1st null could be pci_config_update
540                                          -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL,
541                                          NULL, dev);
542
543         if (pci_dev == NULL) {
544             PrintError("Failed to register VIDEO %d with PCI\n", i);
545             return -1;
546         } else{
547             PrintDebug("Registering PCI_VIDEO succeeded\n");
548         }
549         //Need to set some pci_dev->config_header.vendor_id type variables
550
551         pci_dev->config_header.vendor_id = 0x1013;
552         pci_dev->config_header.device_id = 0x00B8;
553         pci_dev->config_header.revision = 0x00;
554
555         //If we treat video as a VGA device than below is correct
556         //If treated as a VGA compatible controller, which has mapping
557         //0xA0000-0xB0000 and I/O addresses 0x3B0-0x3BB than change
558         //#define from VGA to 0
559
560         //pci_dev->config_header.class = 0x00;
561         //pci_dev->config_header.subclass = 0x01;
562
563         pci_dev->config_header.class = 0x03;
564         pci_dev->config_header.subclass = 0x00;
565         pci_dev->config_header.prog_if = 0x00;
566
567
568         //We have a subsystem ID, but optional to provide:  1AF4:1100
569         pci_dev->config_header.subsystem_vendor_id = 0x1AF4;
570         pci_dev->config_header.subsystem_id = 0x1100;
571         //pci_dev->config_header.header_type = 0x00;
572         pci_dev->config_header.command = 0x03;
573         video_state->pci_dev = pci_dev;
574     }
575
576     PrintDebug("Video: init complete\n");
577     return 0;
578 }
579
580 device_register("CIRRUS_GFX_CARD", cirrus_gfx_card_init)