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".
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>
37 #include "network_console.h"
41 /* #ifndef DEBUG_CIRRUS_GFX_CARD
43 #define PrintDebug(fmt, args...)
47 #define START_ADDR 0xA0000
48 #define END_ADDR 0xC0000
50 #define SIZE_OF_REGION (END_ADDR - START_ADDR)
53 #define PORT_OFFSET 0x3B0
55 struct video_internal {
56 addr_t video_memory_pa;
57 uint8_t * video_memory;
59 struct vm_device * pci_bus;
60 struct pci_device * pci_dev;
68 uint16_t start_addr_offset;
69 uint16_t old_start_addr_offset;
75 void video_do_in(uint16_t port, void * src, uint_t length){
80 ((uint8_t *)src)[0] = v3_inb(port);
83 ((uint16_t *)src)[0] = v3_inw(port);
86 ((uint32_t *)src)[0] = v3_indw(port);
89 for (i = 0; i < length; i++) {
90 ((uint8_t *)src)[i] = v3_inb(port);
96 void video_do_out(uint16_t port, void * src, uint_t length){
101 v3_outb(port,((uint8_t *)src)[0]);
104 v3_outw(port,((uint16_t *)src)[0]);
107 v3_outdw(port,((uint32_t *)src)[0]);
110 for (i = 0; i < length; i++) {
111 v3_outb(port, ((uint8_t *)src)[i]);
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;
125 PrintDebug("\n\nInside Video Write Memory.\n\n");
126 PrintDebug("Guest address: %p length = %d\n", (void *)guest_addr, length);
128 PrintDebug("Write offset: 0x%x\n", (uint_t)write_offset);
129 PrintDebug("Video_Memory: ");
131 for (i = 0; i < length; i += 2) {
132 PrintDebug("%c", ((char *)(V3_VAddr((void *)guest_addr)))[i]);
136 memcpy(data->video_memory + write_offset, V3_VAddr((void*)guest_addr), length);
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");
146 PrintDebug(" Done.\n");
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);
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);
163 static int video_write_port(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
165 PrintDebug("Video: write port 0x%x...Wrote: ", port);
167 for(i = 0; i < length; i++){
168 PrintDebug("%x", ((uint8_t*)src)[i]);
170 PrintDebug("...Done\n"); */
171 video_do_out(port, src, length);
175 static int video_write_port_store(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
177 PrintDebug("Entering video_write_port_store...port 0x%x\n", port);
179 for(i = 0; i < length; i++){
180 PrintDebug("%x", ((uint8_t*)src)[i]);
182 PrintDebug("...Done\n");
184 struct video_internal * video_state = (struct video_internal *)dev->private_data;
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);
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;
198 PrintDebug("Video: write port 0x%x...Wrote: ", port);
201 for (i = 0; i < length; i++){
202 PrintDebug("%x", ((uint8_t*)src)[i]);
204 PrintDebug("...Done\n");
207 video_state->ports[port - PORT_OFFSET] = 0;
209 memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
211 memcpy(&(video_state->reg_3D5[index]), src, length);
213 index = video_state->ports[port - 1 - PORT_OFFSET];
215 // JRL: Add length check
216 new_start = *((uint8_t *)src);
221 video_state->old_start_addr_offset = video_state->start_addr_offset;
223 video_state->start_addr_offset = (new_start << 8);
229 video_state->start_addr_offset += new_start;
231 diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
234 PrintDebug("Scroll lines = %d\n", diff);
236 send_scroll(video_state->client_fd, diff, video_state->video_memory);
241 video_state->cursor_addr = new_start << 8;
248 video_state->cursor_addr += new_start;
250 x = ((video_state->cursor_addr) % 80) + 1;
251 y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
253 PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
255 send_cursor_update(video_state->client_fd, x, y);
262 video_do_out(port, src, length);
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;
273 PrintDebug("Entering write_port_3C5....port 0x%x\n", port);
276 for(i = 0; i < length; i++){
277 PrintDebug("%x", ((uint8_t*)src)[i]);
279 PrintDebug("...Done\n");
282 video_state->ports[port - PORT_OFFSET] = 0;
283 memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
285 index = video_state->ports[port - 1 - PORT_OFFSET];
287 memcpy(&(video_state->reg_3C4[index]), src, length);
288 video_do_out(port, src, length);
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;
296 PrintDebug("Entering write_port_3CF....port 0x%x\n", port);
300 for(i = 0; i < length; i++){
301 PrintDebug("%x", ((uint8_t*)src)[i]);
303 PrintDebug("...Done\n");
306 video_state->ports[port - PORT_OFFSET] = 0;
307 memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
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);
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;
321 video_state->ports[port - PORT_OFFSET] = 0;
322 memcpy(video_state->ports + (port - PORT_OFFSET), src, length);
324 } else if (length == 2) {
325 uint16_t new_start = *((uint16_t *)src);
326 uint16_t cursor_start = *((uint16_t *)src);;
328 //Updating the cursor
329 if ((cursor_start & 0x00FF) == 0x000E) {
331 cursor_start = (cursor_start & 0xFF00);
332 video_state->cursor_addr = cursor_start;
334 } else if ((cursor_start & 0x00FF) == 0x000F) {
338 video_state->cursor_addr += ((cursor_start >> 8) & 0x00FF);
340 x = ((video_state->cursor_addr) % 80) + 1;
341 y = (((video_state->cursor_addr) / 80) - ((video_state->start_addr_offset / 80))) + 1;
343 PrintDebug("New Cursor Location; X=%d Y=%d\n", x, y);
345 send_cursor_update(video_state->client_fd, x, y);
348 //Checking to see if scrolling is needed
349 if ((new_start & 0x00FF) == 0x000C) {
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;
355 } else if ((new_start & 0x00FF) == 0x000D) {
358 video_state->start_addr_offset += ((new_start >> 8) & 0x00FF);
360 diff = video_state->start_addr_offset - video_state->old_start_addr_offset;
363 PrintDebug("Scroll lines = %d\n", diff);
365 send_scroll(video_state->client_fd, diff, video_state->video_memory+0x18000);
372 video_do_out(port, src, length);
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)));
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");
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");
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");
396 static int cirrus_gfx_card_free(struct vm_device * dev) {
397 v3_unhook_mem(dev->vm, START_ADDR);
401 static int cirrus_gfx_card_reset_device(struct vm_device * dev) {
402 PrintDebug("Video: reset device\n");
406 static int cirrus_gfx_card_start_device(struct vm_device * dev) {
407 PrintDebug("Video: start device\n");
411 static int cirrus_gfx_card_stop_device(struct vm_device * dev) {
412 PrintDebug("Video: stop device\n");
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,
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 * dev_id = v3_cfg_val(cfg, "ID");
428 struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, video_state);
430 if (v3_attach_device(vm, dev) == -1) {
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, 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, 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)