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.


ca1e0bad57d6076ded074e419f878ee0ab567e63
[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 #include <devices/cirrus_gfx_card.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_emulator.h>
25 #include <palacios/vmm_decoder.h>
26 #include <palacios/vm_guest_mem.h>
27 #include <palacios/vmm_decoder.h>
28 #include <palacios/vmm_paging.h>
29 #include <palacios/vmm_instr_emulator.h>
30 #include <palacios/vm_guest_mem.h>
31 #include <palacios/vmm_socket.h>
32 #include <palacios/vmm_host_events.h>
33 #include <devices/pci.h>
34 #include <devices/pci_types.h>
35
36 //#include "network_console.h"
37
38
39
40 /* #ifndef DEBUG_CIRRUS_GFX_CARD
41 #undef PrintDebug
42 #define PrintDebug(fmt, args...)
43 #endif */
44
45
46 #define START_ADDR 0xA0000
47 #define END_ADDR 0xC0000
48
49 #define SIZE_OF_REGION (END_ADDR - START_ADDR)
50
51 #define PASSTHROUGH 1
52 #define PORT_OFFSET 0x3B0
53
54 struct video_internal {
55     addr_t video_memory_pa;
56     uint8_t * video_memory;
57     
58     struct vm_device * pci_bus;
59     struct pci_device * pci_dev;
60
61     int client_fd;
62
63     uint_t screen_bottom;
64     uint_t ports[44];
65     uint8_t reg_3C4[256];
66     uint8_t reg_3CE[256];
67     uint16_t start_addr_offset;
68     uint16_t old_start_addr_offset;
69     uint16_t cursor_addr;
70     uint8_t reg_3D5[25];
71     
72 };
73
74 void video_do_in(uint16_t port, void * src, uint_t length){
75 #if PASSTHROUGH
76     uint_t i;
77     switch (length) {
78         case 1:
79             ((uint8_t *)src)[0] = v3_inb(port);
80             break;
81         case 2:
82             ((uint16_t *)src)[0] = v3_inw(port);
83             break;
84         case 4:
85             ((uint32_t *)src)[0] = v3_indw(port);
86             break;
87         default:
88             for (i = 0; i < length; i++) { 
89                 ((uint8_t *)src)[i] = v3_inb(port);
90             }
91     }
92 #endif
93 }
94
95 void video_do_out(uint16_t port, void * src, uint_t length){
96 #if PASSTHROUGH
97     uint_t i;
98     switch (length) {
99         case 1:
100             v3_outb(port,((uint8_t *)src)[0]);
101             break;
102         case 2:
103             v3_outw(port,((uint16_t *)src)[0]);
104             break;
105         case 4:
106             v3_outdw(port,((uint32_t *)src)[0]);
107             break;
108         default:
109             for (i = 0; i < length; i++) { 
110                 v3_outb(port, ((uint8_t *)src)[i]);
111             }
112     }
113 #endif
114 }
115
116 static int video_write_mem(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data) {
117     struct vm_device * dev = (struct vm_device *)priv_data;
118     struct video_internal * data = (struct video_internal *)dev->private_data;
119     addr_t write_offset = guest_addr - START_ADDR;
120 //    uint_t difference = 0x18000;
121 //    int i = 0;
122
123     /*
124     PrintDebug("\n\nInside Video Write Memory.\n\n");
125     PrintDebug("Guest address: %p length = %d\n", (void *)guest_addr, length);
126
127     PrintDebug("Write offset: 0x%x\n", (uint_t)write_offset);
128     PrintDebug("Video_Memory: ");
129
130     for (i = 0; i < length; i += 2) {
131         PrintDebug("%c", ((char *)(V3_VAddr((void *)guest_addr)))[i]);
132     }
133     */
134 #if PASSTHROUGH
135     memcpy(data->video_memory + write_offset, V3_VAddr((void*)guest_addr), length);
136 #endif
137
138
139 /*    if (send_update(data->client_fd, data->video_memory + difference, write_offset-difference, data->start_addr_offset, length) == -1) {
140         PrintError("Error sending update to client\n");
141         return -1;
142     }
143 */
144     // PrintDebug(" Done.\n");
145     return length;
146 }
147
148 static int video_read_port(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data ) {
149     PrintDebug("Video: Read port 0x%x\n",port);
150     video_do_in(port, dest, length);
151     return length;
152 }
153
154 static int video_read_port_generic(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
155     memset(dest, 0, length);
156     video_do_in(port, dest, length);
157     return length;
158 }
159
160
161 static int video_write_port(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
162     
163       PrintDebug("Video: write port 0x%x...Wrote: ", port);
164       uint_t i;
165       for(i = 0; i < length; i++){
166       PrintDebug("%x", ((uint8_t*)dest)[i]);
167       }
168       PrintDebug("...Done\n");
169     video_do_out(port, dest, length);
170     return length;
171 }
172
173 static int video_write_port_store(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
174     
175       PrintDebug("Entering video_write_port_store...port 0x%x\n", port);
176       uint_t i;
177       for(i = 0; i < length; i++){
178       PrintDebug("%x", ((uint8_t*)dest)[i]);
179       }
180       PrintDebug("...Done\n"); 
181     
182     struct video_internal * video_state = (struct video_internal *)priv_data;
183
184     video_state->ports[port - PORT_OFFSET] = 0;
185     memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
186     video_do_out(port, dest, length);
187
188     return length;
189 }
190
191 static int video_write_port_3D5(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
192     struct video_internal * video_state = (struct video_internal *)priv_data;
193     uint8_t new_start = 0;
194     uint_t index = 0;
195
196     PrintDebug("Video: write port 0x%x...Wrote: ", port);
197     {
198         uint_t i = 0;
199         for (i = 0; i < length; i++){
200             PrintDebug("%x", ((uint8_t*)dest)[i]);
201         }
202         PrintDebug("...Done\n");
203     }
204
205     video_state->ports[port - PORT_OFFSET] = 0;
206
207     memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
208
209     memcpy(&(video_state->reg_3D5[index]), dest, length);
210
211     index = video_state->ports[port - 1 - PORT_OFFSET];
212
213     // JRL: Add length check
214     new_start = *((uint8_t *)dest);
215
216
217     switch (index) {
218         case 0x0c:
219             video_state->old_start_addr_offset = video_state->start_addr_offset;
220
221             video_state->start_addr_offset = (new_start << 8);
222
223             break;
224         case 0x0d: {
225             int diff = 0;
226
227             video_state->start_addr_offset += new_start;
228
229             diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
230             diff /= 80;
231
232             PrintDebug("Scroll lines = %d\n", diff);
233
234 //          send_scroll(video_state->client_fd, diff, video_state->video_memory);
235
236             break;
237         }
238         case 0x0E:
239             video_state->cursor_addr = new_start << 8;
240
241             break;
242         case 0x0F: {
243             uint_t x = 0;
244             uint_t y = 0;
245
246             video_state->cursor_addr += new_start;
247            
248             x = ((video_state->cursor_addr) % 80) + 1;
249             y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
250             
251             PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
252             
253 //          send_cursor_update(video_state->client_fd, x, y);
254             break;
255         }
256         default:
257             break;
258     }
259
260     video_do_out(port, dest, length);
261
262     return length;
263 }
264
265
266 static int video_write_port_3C5(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data ) {
267     struct video_internal * video_state = (struct video_internal *)priv_data;
268     uint_t index = 0;
269
270
271     PrintDebug("Entering write_port_3C5....port 0x%x\n", port);
272     {
273         uint_t i = 0;
274         for(i = 0; i < length; i++){
275             PrintDebug("%x", ((uint8_t*)dest)[i]);
276         }
277         PrintDebug("...Done\n");
278     }
279
280     video_state->ports[port - PORT_OFFSET] = 0;
281     memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
282
283     index = video_state->ports[port - 1 - PORT_OFFSET];
284
285     memcpy(&(video_state->reg_3C4[index]), dest, length);
286     video_do_out(port, dest, length);
287
288     return length;
289 }
290
291 static int video_write_port_3CF(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
292     struct video_internal * video_state = (struct video_internal *)priv_data;
293
294     PrintDebug("Entering write_port_3CF....port 0x%x\n", port);
295
296     {
297         uint_t i = 0;
298         for(i = 0; i < length; i++){
299             PrintDebug("%x", ((uint8_t*)dest)[i]);
300         }
301         PrintDebug("...Done\n");
302     }
303
304     video_state->ports[port - PORT_OFFSET] = 0;
305     memcpy(video_state->ports + (port - PORT_OFFSET), dest, length); 
306
307     uint_t index = video_state->ports[port - 1 - PORT_OFFSET];
308     memcpy(&(video_state->reg_3CE[index]), dest, length);
309     video_do_out(port, dest, length);
310     return length;
311 }
312
313 static int video_write_port_3D4(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data){
314     struct video_internal * video_state = (struct video_internal *)priv_data;
315
316 #if 1
317     if (length == 1) {
318
319         video_state->ports[port - PORT_OFFSET] = 0;
320         memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
321
322     } else if (length == 2) {
323         uint16_t new_start = *((uint16_t *)dest);
324         uint16_t cursor_start = *((uint16_t *)dest);;
325
326         //Updating the cursor
327         if ((cursor_start & 0x00FF) == 0x000E) {
328
329             cursor_start = (cursor_start & 0xFF00);
330             video_state->cursor_addr = cursor_start;
331
332         } else if ((cursor_start & 0x00FF) == 0x000F) {
333             uint_t x = 0;
334             uint_t y = 0;
335
336             video_state->cursor_addr += ((cursor_start >> 8) & 0x00FF);
337
338             x = ((video_state->cursor_addr) % 80) + 1;
339             y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
340
341             PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
342
343 //          send_cursor_update(video_state->client_fd, x, y);
344         }
345
346         //Checking to see if scrolling is needed
347         if ((new_start & 0x00FF) == 0x000C) {
348
349             video_state->old_start_addr_offset = video_state->start_addr_offset;
350             new_start = (new_start & 0xFF00);
351             video_state->start_addr_offset = new_start;
352
353         } else if ((new_start & 0x00FF) == 0x000D) {
354             int diff = 0;
355
356             video_state->start_addr_offset += ((new_start >> 8) & 0x00FF);
357
358             diff =  video_state->start_addr_offset - video_state->old_start_addr_offset;
359             diff /= 80;
360
361             PrintDebug("Scroll lines = %d\n", diff);
362
363 //          send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
364         }
365     } else {
366         // JRL ??
367         return -1;
368     }
369 #endif 
370     video_do_out(port, dest, length);
371     return length;
372 }
373
374 static int video_write_mem_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data) {;
375     PrintDebug("Video write mem region guest_addr: 0x%p, src: 0x%p, length: %d, Value?= %x\n", (void *)guest_addr, dest, length, *((uint32_t *)V3_VAddr((void *)guest_addr)));
376     return length;
377 }
378
379 static int video_read_mem_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
380     PrintDebug("Video:  Within video_read_mem_region\n");
381     return length;
382 }
383
384 static int video_write_io_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
385     PrintDebug("Video:  Within video_write_io_region\n");
386     return length;
387 }
388
389 static int video_read_io_region(struct guest_info * core, addr_t guest_addr, void * dest, uint_t length, void * priv_data){
390     PrintDebug("Video:  Within video_read_io_region\n");
391     return length;
392 }
393
394 static int cirrus_gfx_card_free(struct vm_device * dev) {
395     v3_unhook_mem(dev->vm, V3_MEM_CORE_ANY, START_ADDR);
396     return 0;
397 }
398
399 /*
400 static int cirrus_gfx_card_reset_device(struct vm_device * dev) {
401     PrintDebug("Video: reset device\n");
402     return 0;
403 }
404
405 static int cirrus_gfx_card_start_device(struct vm_device * dev) {
406     PrintDebug("Video: start device\n");
407     return 0;
408 }
409
410 static int cirrus_gfx_card_stop_device(struct vm_device * dev) {
411     PrintDebug("Video: stop device\n");
412     return 0;
413 }
414 */
415 static struct v3_device_ops dev_ops = {
416     .free = (int (*)(void *))cirrus_gfx_card_free,
417 //    .reset = cirrus_gfx_card_reset_device,
418 //    .start = cirrus_gfx_card_start_device,
419 //    .stop = cirrus_gfx_card_stop_device,
420 };
421
422 static int cirrus_gfx_card_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg){
423     struct video_internal * video_state = (struct video_internal *)V3_Malloc(sizeof(struct video_internal));
424 //    struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
425     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
426     char * dev_id = v3_cfg_val(cfg, "ID");
427
428     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, video_state);
429
430     if (dev == NULL) {
431         PrintError("Could not attach device %s\n", dev_id);
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, V3_MEM_CORE_ANY, 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, V3_MEM_CORE_ANY, 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)