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.


integrated new configuration system
[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, v3_cfg_tree_t * cfg){
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     char * name = v3_cfg_val(cfg, "name");
427
428     struct vm_device * dev = v3_allocate_device("TEXT_GFX_CARD", &dev_ops, video_state);
429
430     if (v3_attach_device(vm, dev) == -1) {
431         PrintError("Could not attach device %s\n", "TEXT_GFX_CARD");
432         return -1;
433     }
434
435     PrintDebug("video: init_device\n");
436     PrintDebug("Num Pages=%d\n", SIZE_OF_REGION / 4096);
437
438     video_state->video_memory_pa = (addr_t)V3_AllocPages(SIZE_OF_REGION / 4096);
439     video_state->video_memory = V3_VAddr((void *)video_state->video_memory_pa);
440
441     memset(video_state->video_memory, 0, SIZE_OF_REGION);
442
443
444     v3_dev_hook_io(dev, 0x3b0, &video_read_port, &video_write_port);
445     v3_dev_hook_io(dev, 0x3b1, &video_read_port, &video_write_port);
446     v3_dev_hook_io(dev, 0x3b2, &video_read_port, &video_write_port);
447     v3_dev_hook_io(dev, 0x3b3, &video_read_port, &video_write_port);
448     v3_dev_hook_io(dev, 0x3b4, &video_read_port, &video_write_port);
449     v3_dev_hook_io(dev, 0x3b5, &video_read_port, &video_write_port);
450     v3_dev_hook_io(dev, 0x3b6, &video_read_port, &video_write_port);
451     v3_dev_hook_io(dev, 0x3b7, &video_read_port, &video_write_port);
452     v3_dev_hook_io(dev, 0x3b8, &video_read_port, &video_write_port);
453     v3_dev_hook_io(dev, 0x3b9, &video_read_port, &video_write_port);
454     v3_dev_hook_io(dev, 0x3ba, &video_read_port, &video_write_port);
455     v3_dev_hook_io(dev, 0x3bb, &video_read_port, &video_write_port);
456     v3_dev_hook_io(dev, 0x3c0, &video_read_port, &video_write_port_store);
457     v3_dev_hook_io(dev, 0x3c1, &video_read_port, &video_write_port);
458     v3_dev_hook_io(dev, 0x3c2, &video_read_port, &video_write_port_store);
459     v3_dev_hook_io(dev, 0x3c3, &video_read_port, &video_write_port);
460     v3_dev_hook_io(dev, 0x3c4, &video_read_port, &video_write_port_store);
461     v3_dev_hook_io(dev, 0x3c5, &video_read_port, &video_write_port_3C5);
462     v3_dev_hook_io(dev, 0x3c6, &video_read_port, &video_write_port_store);
463     v3_dev_hook_io(dev, 0x3c7, &video_read_port, &video_write_port);
464     v3_dev_hook_io(dev, 0x3c8, &video_read_port, &video_write_port_store);
465     v3_dev_hook_io(dev, 0x3c9, &video_read_port, &video_write_port_store);
466     v3_dev_hook_io(dev, 0x3ca, &video_read_port, &video_write_port);
467     v3_dev_hook_io(dev, 0x3cb, &video_read_port, &video_write_port);
468     v3_dev_hook_io(dev, 0x3cc, &video_read_port, &video_write_port);
469     v3_dev_hook_io(dev, 0x3cd, &video_read_port, &video_write_port);
470     v3_dev_hook_io(dev, 0x3ce, &video_read_port, &video_write_port_store);
471     v3_dev_hook_io(dev, 0x3cf, &video_read_port, &video_write_port_3CF);
472     v3_dev_hook_io(dev, 0x3d0, &video_read_port, &video_write_port);
473     v3_dev_hook_io(dev, 0x3d1, &video_read_port, &video_write_port);
474     v3_dev_hook_io(dev, 0x3d2, &video_read_port, &video_write_port);
475     v3_dev_hook_io(dev, 0x3d3, &video_read_port, &video_write_port);
476     v3_dev_hook_io(dev, 0x3d4, &video_read_port, &video_write_port_3D4);
477     v3_dev_hook_io(dev, 0x3d5, &video_read_port, &video_write_port_3D5);
478     v3_dev_hook_io(dev, 0x3d6, &video_read_port, &video_write_port);
479     v3_dev_hook_io(dev, 0x3d7, &video_read_port, &video_write_port);
480     v3_dev_hook_io(dev, 0x3d8, &video_read_port, &video_write_port);
481     v3_dev_hook_io(dev, 0x3d9, &video_read_port, &video_write_port);
482     v3_dev_hook_io(dev, 0x3da, &video_read_port_generic, &video_write_port);
483     v3_dev_hook_io(dev, 0x3db, &video_read_port, &video_write_port);
484     v3_dev_hook_io(dev, 0x3dc, &video_read_port, &video_write_port);
485     v3_dev_hook_io(dev, 0x3dd, &video_read_port, &video_write_port);
486     v3_dev_hook_io(dev, 0x3de, &video_read_port, &video_write_port);
487     v3_dev_hook_io(dev, 0x3df, &video_read_port, &video_write_port);
488
489
490     PrintDebug("PA of array: %p\n", (void *)video_state->video_memory_pa);
491
492
493 #if PASSTHROUGH
494     if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, START_ADDR, &video_write_mem, dev) == -1){
495         PrintDebug("\n\nVideo Hook failed.\n\n");
496     }
497 #else
498     if (v3_hook_write_mem(vm, START_ADDR, END_ADDR, video_memory_pa, &video_write_mem, dev) == -1){
499         PrintDebug("\n\nVideo Hook failed.\n\n");
500     }
501 #endif
502
503     PrintDebug("Video: Getting client connection\n");
504
505     video_state->client_fd = get_client_connection(vm);
506
507     PrintDebug("Video: Client connection established\n");
508
509     video_state->screen_bottom = 25;
510
511     video_state->pci_bus = pci_bus;
512
513     if (video_state->pci_bus == NULL) {
514         PrintError("Could not find PCI device\n");
515         return -1;
516     } else {
517         struct v3_pci_bar bars[6];
518         struct pci_device * pci_dev = NULL;
519
520         int i;
521         for (i = 0; i < 6; i++) {
522             bars[i].type = PCI_BAR_NONE;
523         }
524
525         bars[0].type = PCI_BAR_MEM32;
526         bars[0].num_pages = 8192;
527         bars[0].default_base_addr = 0xf0000000;
528
529         bars[0].mem_read = video_read_mem_region;
530         bars[0].mem_write = video_write_mem_region;
531
532         bars[1].type = PCI_BAR_MEM32;
533         bars[1].num_pages = 1;
534         bars[1].default_base_addr = 0xf2000000;
535     
536         bars[1].mem_read = video_read_io_region;
537         bars[1].mem_write = video_write_io_region;
538         //-1 Means autoassign
539         //                                                     Not sure if STD
540         pci_dev = v3_pci_register_device(video_state->pci_bus, PCI_STD_DEVICE, 0,
541                                          //or0  1st null could be pci_config_update
542                                          -1, 0, "CIRRUS_GFX_CARD", bars, NULL, NULL,
543                                          NULL, dev);
544
545         if (pci_dev == NULL) {
546             PrintError("Failed to register VIDEO %d with PCI\n", i);
547             return -1;
548         } else{
549             PrintDebug("Registering PCI_VIDEO succeeded\n");
550         }
551         //Need to set some pci_dev->config_header.vendor_id type variables
552
553         pci_dev->config_header.vendor_id = 0x1013;
554         pci_dev->config_header.device_id = 0x00B8;
555         pci_dev->config_header.revision = 0x00;
556
557         //If we treat video as a VGA device than below is correct
558         //If treated as a VGA compatible controller, which has mapping
559         //0xA0000-0xB0000 and I/O addresses 0x3B0-0x3BB than change
560         //#define from VGA to 0
561
562         //pci_dev->config_header.class = 0x00;
563         //pci_dev->config_header.subclass = 0x01;
564
565         pci_dev->config_header.class = 0x03;
566         pci_dev->config_header.subclass = 0x00;
567         pci_dev->config_header.prog_if = 0x00;
568
569
570         //We have a subsystem ID, but optional to provide:  1AF4:1100
571         pci_dev->config_header.subsystem_vendor_id = 0x1AF4;
572         pci_dev->config_header.subsystem_id = 0x1100;
573         //pci_dev->config_header.header_type = 0x00;
574         pci_dev->config_header.command = 0x03;
575         video_state->pci_dev = pci_dev;
576     }
577
578     PrintDebug("Video: init complete\n");
579     return 0;
580 }
581
582 device_register("CIRRUS_GFX_CARD", cirrus_gfx_card_init)