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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
15 * Author: Robdert Deloatch <rtdeloatch@gmail.com>
16 * Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
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 <interfaces/vmm_socket.h>
32 #include <palacios/vmm_host_events.h>
33 #include <devices/pci.h>
34 #include <devices/pci_types.h>
36 //#include "network_console.h"
40 /* #ifndef DEBUG_CIRRUS_GFX_CARD
42 #define PrintDebug(fmt, args...)
46 #define START_ADDR 0xA0000
47 #define END_ADDR 0xC0000
49 #define SIZE_OF_REGION (END_ADDR - START_ADDR)
52 #define PORT_OFFSET 0x3B0
54 struct video_internal {
55 addr_t video_memory_pa;
56 uint8_t * video_memory;
58 struct vm_device * pci_bus;
59 struct pci_device * pci_dev;
67 uint16_t start_addr_offset;
68 uint16_t old_start_addr_offset;
74 void video_do_in(uint16_t port, void * src, uint_t length){
79 ((uint8_t *)src)[0] = v3_inb(port);
82 ((uint16_t *)src)[0] = v3_inw(port);
85 ((uint32_t *)src)[0] = v3_indw(port);
88 for (i = 0; i < length; i++) {
89 ((uint8_t *)src)[i] = v3_inb(port);
95 void video_do_out(uint16_t port, void * src, uint_t length){
100 v3_outb(port,((uint8_t *)src)[0]);
103 v3_outw(port,((uint16_t *)src)[0]);
106 v3_outdw(port,((uint32_t *)src)[0]);
109 for (i = 0; i < length; i++) {
110 v3_outb(port, ((uint8_t *)src)[i]);
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;
124 PrintDebug("\n\nInside Video Write Memory.\n\n");
125 PrintDebug("Guest address: %p length = %d\n", (void *)guest_addr, length);
127 PrintDebug("Write offset: 0x%x\n", (uint_t)write_offset);
128 PrintDebug("Video_Memory: ");
130 for (i = 0; i < length; i += 2) {
131 PrintDebug("%c", ((char *)(V3_VAddr((void *)guest_addr)))[i]);
135 memcpy(data->video_memory + write_offset, V3_VAddr((void*)guest_addr), length);
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");
144 // PrintDebug(" Done.\n");
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);
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);
161 static int video_write_port(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
163 PrintDebug("Video: write port 0x%x...Wrote: ", port);
165 for(i = 0; i < length; i++){
166 PrintDebug("%x", ((uint8_t*)dest)[i]);
168 PrintDebug("...Done\n");
169 video_do_out(port, dest, length);
173 static int video_write_port_store(struct guest_info * dev, uint16_t port, void * dest, uint_t length, void * priv_data) {
175 PrintDebug("Entering video_write_port_store...port 0x%x\n", port);
177 for(i = 0; i < length; i++){
178 PrintDebug("%x", ((uint8_t*)dest)[i]);
180 PrintDebug("...Done\n");
182 struct video_internal * video_state = (struct video_internal *)priv_data;
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);
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;
196 PrintDebug("Video: write port 0x%x...Wrote: ", port);
199 for (i = 0; i < length; i++){
200 PrintDebug("%x", ((uint8_t*)dest)[i]);
202 PrintDebug("...Done\n");
205 video_state->ports[port - PORT_OFFSET] = 0;
207 memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
209 memcpy(&(video_state->reg_3D5[index]), dest, length);
211 index = video_state->ports[port - 1 - PORT_OFFSET];
213 // JRL: Add length check
214 new_start = *((uint8_t *)dest);
219 video_state->old_start_addr_offset = video_state->start_addr_offset;
221 video_state->start_addr_offset = (new_start << 8);
227 video_state->start_addr_offset += new_start;
229 diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
232 PrintDebug("Scroll lines = %d\n", diff);
234 // send_scroll(video_state->client_fd, diff, video_state->video_memory);
239 video_state->cursor_addr = new_start << 8;
246 video_state->cursor_addr += new_start;
248 x = ((video_state->cursor_addr) % 80) + 1;
249 y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
251 PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
253 // send_cursor_update(video_state->client_fd, x, y);
260 video_do_out(port, dest, length);
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;
271 PrintDebug("Entering write_port_3C5....port 0x%x\n", port);
274 for(i = 0; i < length; i++){
275 PrintDebug("%x", ((uint8_t*)dest)[i]);
277 PrintDebug("...Done\n");
280 video_state->ports[port - PORT_OFFSET] = 0;
281 memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
283 index = video_state->ports[port - 1 - PORT_OFFSET];
285 memcpy(&(video_state->reg_3C4[index]), dest, length);
286 video_do_out(port, dest, length);
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;
294 PrintDebug("Entering write_port_3CF....port 0x%x\n", port);
298 for(i = 0; i < length; i++){
299 PrintDebug("%x", ((uint8_t*)dest)[i]);
301 PrintDebug("...Done\n");
304 video_state->ports[port - PORT_OFFSET] = 0;
305 memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
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);
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;
319 video_state->ports[port - PORT_OFFSET] = 0;
320 memcpy(video_state->ports + (port - PORT_OFFSET), dest, length);
322 } else if (length == 2) {
323 uint16_t new_start = *((uint16_t *)dest);
324 uint16_t cursor_start = *((uint16_t *)dest);;
326 //Updating the cursor
327 if ((cursor_start & 0x00FF) == 0x000E) {
329 cursor_start = (cursor_start & 0xFF00);
330 video_state->cursor_addr = cursor_start;
332 } else if ((cursor_start & 0x00FF) == 0x000F) {
336 video_state->cursor_addr += ((cursor_start >> 8) & 0x00FF);
338 x = ((video_state->cursor_addr) % 80) + 1;
339 y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
341 PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
343 // send_cursor_update(video_state->client_fd, x, y);
346 //Checking to see if scrolling is needed
347 if ((new_start & 0x00FF) == 0x000C) {
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;
353 } else if ((new_start & 0x00FF) == 0x000D) {
356 video_state->start_addr_offset += ((new_start >> 8) & 0x00FF);
358 diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
361 PrintDebug("Scroll lines = %d\n", diff);
363 // send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
370 video_do_out(port, dest, length);
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)));
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");
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");
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");
394 static int cirrus_gfx_card_free(struct vm_device * dev) {
395 v3_unhook_mem(dev->vm, V3_MEM_CORE_ANY, START_ADDR);
400 static int cirrus_gfx_card_reset_device(struct vm_device * dev) {
401 PrintDebug("Video: reset device\n");
405 static int cirrus_gfx_card_start_device(struct vm_device * dev) {
406 PrintDebug("Video: start device\n");
410 static int cirrus_gfx_card_stop_device(struct vm_device * dev) {
411 PrintDebug("Video: stop device\n");
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,
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");
428 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, video_state);
431 PrintError("Could not attach device %s\n", dev_id);
435 PrintDebug("video: init_device\n");
436 PrintDebug("Num Pages=%d\n", SIZE_OF_REGION / 4096);
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);
441 memset(video_state->video_memory, 0, SIZE_OF_REGION);
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);
490 PrintDebug("PA of array: %p\n", (void *)video_state->video_memory_pa);
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");
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");
503 PrintDebug("Video: Getting client connection\n");
505 //video_state->client_fd = get_client_connection(vm);
507 PrintDebug("Video: Client connection established\n");
509 video_state->screen_bottom = 25;
511 video_state->pci_bus = pci_bus;
513 if (video_state->pci_bus == NULL) {
514 PrintError("Could not find PCI device\n");
517 struct v3_pci_bar bars[6];
518 struct pci_device * pci_dev = NULL;
521 for (i = 0; i < 6; i++) {
522 bars[i].type = PCI_BAR_NONE;
525 bars[0].type = PCI_BAR_MEM32;
526 bars[0].num_pages = 8192;
527 bars[0].default_base_addr = 0xf0000000;
529 bars[0].mem_read = video_read_mem_region;
530 bars[0].mem_write = video_write_mem_region;
532 bars[1].type = PCI_BAR_MEM32;
533 bars[1].num_pages = 1;
534 bars[1].default_base_addr = 0xf2000000;
536 bars[1].mem_read = video_read_io_region;
537 bars[1].mem_write = video_write_io_region;
538 //-1 Means autoassign
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,
545 if (pci_dev == NULL) {
546 PrintError("Failed to register VIDEO %d with PCI\n", i);
549 PrintDebug("Registering PCI_VIDEO succeeded\n");
551 //Need to set some pci_dev->config_header.vendor_id type variables
553 pci_dev->config_header.vendor_id = 0x1013;
554 pci_dev->config_header.device_id = 0x00B8;
555 pci_dev->config_header.revision = 0x00;
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
562 //pci_dev->config_header.class = 0x00;
563 //pci_dev->config_header.subclass = 0x01;
565 pci_dev->config_header.class = 0x03;
566 pci_dev->config_header.subclass = 0x00;
567 pci_dev->config_header.prog_if = 0x00;
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;
578 PrintDebug("Video: init complete\n");
582 device_register("CIRRUS_GFX_CARD", cirrus_gfx_card_init)