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) 2011, Peter Dinda <pdinda@northwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Peter Dinda <pdinda@northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_types.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_io.h>
28 #define MEM_REGION_START 0xa0000
29 #define MEM_REGION_END 0xc0000
30 #define MEM_REGION_NUM_PAGES (((MEM_REGION_END)-(MEM_REGION_START))/4096)
32 #define MAP_SIZE 65536
35 typedef uint8_t *vga_map; // points to MAP_SIZE data
38 #define VGA_MISC_OUT_READ 0x3cc
39 #define VGA_MISC_OUT_WRITE 0x3c2
41 #define VGA_INPUT_STAT0_READ 0x3c2
43 #define VGA_INPUT_STAT1_READ_MONO 0x3ba
44 #define VGA_INPUT_STAT1_READ_COLOR 0x3da
46 #define VGA_FEATURE_CONTROL_READ 0x3ca
47 #define VGA_FEATURE_CONTROL_WRITE_MONO 0x3ba
48 #define VGA_FEATURE_CONTROL_WRITE_COLOR 0x3da
50 #define VGA_VIDEO_SUBSYS_ENABLE 0x3c3
52 #define VGA_SEQUENCER_ADDRESS 0x3c4
53 #define VGA_SEQUENCER_DATA 0x3c5
54 #define VGA_SEQUENCER_NUM 5
57 #define VGA_CRT_CONTROLLER_ADDRESS_MONO 0x3b4
58 #define VGA_CRT_CONTROLLER_ADDRESS_COLOR 0x3d4
59 #define VGA_CRT_CONTROLLER_DATA_MONO 0x3b5
60 #define VGA_CRT_CONTROLLER_DATA_COLOR 0x3d5
61 #define VGA_CRT_CONTROLLER_NUM 25
64 #define VGA_GRAPHICS_CONTROLLER_ADDRESS 0x3ce
65 #define VGA_GRAPHICS_CONTROLLER_DATA 0x3cf
66 #define VGA_GRAPHICS_CONTROLLER_NUM 9
68 #define VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE 0x3c0
69 #define VGA_ATTRIBUTE_CONTROLLER_READ 0x3c1
70 #define VGA_ATTRIBUTE_CONTROLLER_NUM 21
72 #define VGA_DAC_WRITE_ADDR 0x3c8
73 #define VGA_DAC_READ_ADDR 0x3c7
74 #define VGA_DAC_DATA 0x3c8
75 #define VGA_DAC_PIXEL_MASK 0x3c6
77 #define VGA_DAC_NUM_ENTRIES 256
79 struct vga_misc_regs {
80 /* Read: 0x3cc; Write: 0x3c2 */
81 struct vga_misc_out_reg vga_misc_out;
83 struct vga_input_stat0_reg vga_input_stat0;
84 /* Read: 0x3?a 3ba for mono; 3da for cga set by misc.io_addr_sel */
85 struct vga_input_stat1_reg vga_input_stat1;
86 /* Read: 0x3ca; Write: 0x3?a 3ba for mono 3da for color - set by misc.io_addr_sel*/
87 struct vga_feature_control_reg vga_feature_control;
88 /* Read: 0x3c3; Write: 0x3c3 */
89 struct vga_video_subsys_enable_reg vga_video_subsys_enable;
90 } __attribute__((packed));
92 struct vga_sequencer_regs {
93 /* Address register is 0x3c4, data register is 0x3c5 */
95 struct vga_sequencer_addr_reg vga_sequencer_addr;
97 /* these can be accessed via the index, offset on start
98 or via the specific regs. For this reason, it is essential
99 that this is all packed and that the order does not change */
101 uint8_t vga_sequencer_regs[0];
104 struct vga_reset_reg vga_reset;
106 struct vga_clocking_mode_reg vga_clocking_mode;
108 struct vga_map_mask_reg vga_map_mask;
110 struct vga_char_map_select_reg vga_char_map_select;
112 struct vga_mem_mode_reg vga_mem_mode;
113 } __attribute__((packed));
115 struct vga_crt_controller_regs {
116 /* Address Register is 0x3b4 or 0x3d4 */
117 /* Data register is 0x3b5 or 0x3d5 based on mono versus color */
118 struct vga_crt_addr_reg vga_crt_addr;
120 /* these can be accessed via the index, offset on start
121 or via the specific regs. For this reason, it is essential
122 that this is all packed and that the order does not change */
124 uint8_t vga_crt_controller_regs[0];
127 vga_horizontal_total_reg vga_horizontal_total;
129 vga_horizontal_display_enable_end_reg vga_horizontal_display_enable_end;
131 vga_start_horizontal_blanking_reg vga_start_horizontal_blanking;
133 struct vga_end_horizontal_blanking_reg vga_end_horizontal_blanking;
135 vga_start_horizontal_retrace_pulse_reg vga_start_horizontal_retrace_pulse;
137 struct vga_end_horizontal_retrace_reg vga_end_horizontal_retrace;
139 vga_vertical_total_reg vga_vertical_total;
141 struct vga_overflow_reg vga_overflow;
143 struct vga_preset_row_scan_reg vga_preset_row_scan;
145 struct vga_max_row_scan_reg vga_row_scan;
147 struct vga_cursor_start_reg vga_cursor_start;
149 struct vga_cursor_end_reg vga_cursor_end;
151 vga_start_address_high_reg vga_start_address_high;
153 vga_start_address_low_reg vga_start_address_low;
155 vga_cursor_location_high_reg vga_cursor_location_high;
157 vga_cursor_location_low_reg vga_cursor_location_low;
159 vga_vertical_retrace_start_reg vga_vertical_retrace_start;
161 struct vga_vertical_retrace_end_reg vga_vertical_retrace_end;
163 vga_vertical_display_enable_end_reg vga_vertical_display_enable;
165 vga_offset_reg vga_offset;
167 struct vga_underline_location_reg vga_underline_location;
169 vga_start_vertical_blanking_reg vga_start_vertical_blanking;
171 vga_end_vertical_blanking_reg vga_end_vertical_blanking;
173 struct vga_crt_mode_control_reg vga_crt_mode_control;
175 vga_line_compare_reg vga_line_compare;
176 } __attribute__((packed));
178 struct vga_graphics_controller_regs {
179 /* Address: 0x3ce Data: 0x3cf */
182 struct vga_graphics_ctrl_addr_reg vga_graphics_ctrl_addr;
184 /* these can be accessed via the index, offset on start
185 or via the specific regs. For this reason, it is essential
186 that this is all packed and that the order does not change */
188 uint8_t vga_graphics_controller_regs[0];
191 struct vga_set_reset_reg vga_set_reset;
193 struct vga_enable_set_reset_reg vga_enable_set_reset;
195 struct vga_color_compare_reg vga_color_compare;
197 struct vga_data_rotate_reg vga_data_rotate;
199 struct vga_read_map_select_reg vga_read_map_select;
201 struct vga_graphics_mode_reg vga_graphics_mode;
203 struct vga_misc_reg vga_misc;
205 struct vga_color_dont_care__reg vga_color_dont_care;
207 vga_bit_mask_reg vga_bit_mask;
208 } __attribute__((packed));
211 struct vga_attribute_contoller_regs {
213 Address AND WRITE: 0x3c0
216 The write protocol is to write the index to 0x3c0 followed by
217 the data. The read protocol is to write the index to 0x3c0
218 and then read from 0x3c1
220 IMPORTANT: write address, write data flips state back to write address
221 write address, read data DOES NOT
223 To reset to write address state, read input status register 1
225 enum { ATTR_ADDR, ATTR_DATA } state; //state of the flip flop
228 struct vga_attribute_controller_address_reg vga_attribute_controller_addr;
232 /* these can be accessed via the index, offset on start
233 or via the specific regs. For this reason, it is essential
234 that this is all packed and that the order does not change */
236 uint8_t vga_attribute_controller_regs[0];
239 vga_internal_palette_regs vga_internal_palette;
241 struct vga_attribute_mode_control_reg vga_attribute_mode_control;
243 vga_overscan_color_reg vga_overscan_color;
245 struct vga_color_plane_enable_reg vga_color_plane_enable;
247 struct vga_horizontal_pixel_pan_reg vga_horizontal_pixel_pan;
249 struct vga_color_select_reg vga_color_select;
250 } __attribute__((packed));
252 struct vga_dac_regs {
253 enum {DAC_READ=0, DAC_WRITE} state;
254 enum {RED=0,GREEN,BLUE} channel;
255 vga_dac_pixel_mask_reg vga_pixel_mask;
256 vga_dac_write_addr_reg vga_dac_write_addr;
257 vga_dac_read_addr_reg vga_dac_read_addr;
258 // the dac_data register is used only to access the registers
259 // and thus has no representation here
260 vga_palette_reg vga_dac_palette[VGA_DAC_NUM_ENTRIES];
261 } __attribute__((packed));
264 struct vga_internal {
265 struct vm_device *dev;
267 struct frame_buf *framebuf; // we render to this
269 // void *mem_store; // This is the region where the memory hooks will go
271 vga_map map[MAP_NUM]; // the maps that the host writes to
273 /* Range of I/O ports here for backward compat with MDA and CGA */
274 struct vga_misc_regs vga_misc;
276 /* Address Register is 0x3b4 or 0x3d4 */
277 /* Data register is 0x3b5 or 0x3d5 based on MDA/CGA/VGA (backward compat) */
278 struct vga_crt_controller_regs vga_crt_controller;
280 /* Address register is 0x3c4, data register is 0x3c5 */
281 struct vga_sequencer_regs vga_sequencer;
283 /* Address: 0x3ce Data: 0x3cf */
284 struct vga_graphics_controller_regs vga_graphics_controller;
287 Address AND WRITE: 0x3c0
291 struct vga_attribute_contoller_regs vga_attribute_controller;
294 address for reads: 0x3c7 (also resets state machine for access to 18 bit regs
295 address for writes: 0x3c8 ("")
297 pixel mask: 0x3c6 - do not write (init to 0xff)
299 struct vga_dac_regs vga_dac;
304 static int vga_write(struct guest_info * core,
312 PrintError("vga: vga_write UNIMPLEMENTED\n");
315 up to 256K mapped through a window of 128K
317 most cards support linear mode as well
319 Need to implement readability too
321 Write extended memory bit to enable all 256K:
323 Sequencer Memory Mode Register (Index 04h) . extended memory
325 Must enable writes before effects happen:
327 Miscellaneous Output Register (Read at 3CCh, Write at 3C2h).ram enable
329 Choose which addresses are supported for CPU writes:
331 Miscellaneous Graphics Register (Index 06h).memory map select
333 00b -- A0000h-BFFFFh (128K region)
334 01b -- A0000h-AFFFFh (64K region)
335 10b -- B0000h-B7FFFh (32K region)
336 11b -- B8000h-BFFFFh (32K region)
338 There are three addressing modes: Chain 4, Odd/Even mode, and normal mode:
340 Chain 4: This mode is used for MCGA emulation in the 320x200 256-color mode. The address is mapped to memory MOD 4 (shifted right 2 places.)
342 Memory model: 64K 32 bit locations; divided into 4 64K bit planes
344 Write Modes - set via Graphics Mode Register (Index 05h).writemode
346 00b -- Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
348 01b -- Write Mode 1: In this mode, data is transferred directly from the 32 bit latch register to display memory, affected only by the Memory Plane Write Enable field. The host data is not used in this mode.
350 10b -- Write Mode 2: In this mode, the bits 3-0 of the host data are replicated across all 8 bits of their respective planes. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
352 11b -- Write Mode 3: In this mode, the data in the Set/Reset field is used as if the Enable Set/Reset field were set to 1111b. Then the host data is first rotated as per the Rotate Count field, then logical ANDed with the value of the Bit Mask field. The resulting value is used on the data obtained from the Set/Reset field in the same way that the Bit Mask field would ordinarily be used. to select which bits come from the expansion of the Set/Reset field and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
354 five stages of a write:
356 write(void *adx, uint8_t x) // or 4 byte?!
360 switch (Write Mode) {
363 x = ROR(x,Rotate Count)
365 // 2. Clone from Host Data or Set/Reset Reg
367 if (Enable Set/Reset[i]) {
368 rx[i]=Set/Reset (expanded to 8 bits)
374 // 3. Logical Operator
376 rx[i] = rx[i] LOP LATCH_REG[i]
377 // LOP = NOP, AND, OR, XOR
382 rx[i] = BITWISE_MUX(rx[i], LATCH_REG[i], Bit Mask Reg);
385 // 5. Selective Write
387 if (Map Mask Reg.Memory Plane Write Enable[i])
388 BUF[TRANSLATE(adx,i)] = rx[i];
393 // 4. Select latch register directly
395 rx[i] = LATCH_REG[i];
397 // 5. Selective Write
399 if (Map Mask Reg.Memory Plane Write Enable[i])
400 BUF[TRANSLATE(adx,i)] = rx[i];
408 Assume linear framebuffer, starting at address buf:
415 static int vga_read(struct guest_info * core,
422 PrintError("vga: vga_read UNIMPLEMENTED\n");
425 Reading, 2 modes, set via Graphics Mode Register (index 05h).Read Mode:
426 0 - a byte from ONE of the 4 planes is returned; which plane is determined by Read Map Select (Read Map Select Register (Index 04h))
427 1 - Compare video memory and reference color (in Color Compare, except those not set in Color Don't Care), each bit in returned result is one comparison between the reference color, and is set to one if true (plane by plane, I assume)
435 static int render(struct vga_internal *vga)
437 PrintError("vga: render UNIMPLEMENTED\n");
442 #define ERR_WRONG_SIZE(op,reg,len,min,max) \
443 if (((len)<(min)) || ((len)>(max))) { \
444 PrintError("vga: %s of %s wrong size (%d bytes, but only %d to %d allowed)\n",(op),(reg),(len),(min),(max)); \
450 static int misc_out_read(struct guest_info *core,
456 struct vga_internal *vga = (struct vga_internal *) priv_data;
458 PrintDebug("vga: misc out read data=0x%x\n", vga->vga_misc.vga_misc_out.val);
460 ERR_WRONG_SIZE("read","misc out",len,1,1);
462 *((uint8_t*)dest) = vga->vga_misc.vga_misc_out.val;
467 static int misc_out_write(struct guest_info *core,
473 struct vga_internal *vga = (struct vga_internal *) priv_data;
475 PrintDebug("vga: misc out write data=0x%x\n", *((uint8_t*)src));
477 ERR_WRONG_SIZE("write","misc out",len,1,1);
479 vga->vga_misc.vga_misc_out.val = *((uint8_t*)src) ;
488 static int input_stat0_read(struct guest_info *core,
494 struct vga_internal *vga = (struct vga_internal *) priv_data;
496 PrintDebug("vga: input stat0 read data=0x%x\n", vga->vga_misc.vga_input_stat0.val);
498 ERR_WRONG_SIZE("read","inpust stat0",len,1,1);
500 *((uint8_t*)dest) = vga->vga_misc.vga_input_stat0.val;
506 static int input_stat1_read(struct guest_info *core,
512 struct vga_internal *vga = (struct vga_internal *) priv_data;
514 PrintDebug("vga: input stat0 (%s) read data=0x%x\n",
515 port==0x3ba ? "mono" : "color",
516 vga->vga_misc.vga_input_stat1.val);
518 ERR_WRONG_SIZE("read","inpust stat1",len,1,1);
520 *((uint8_t*)dest) = vga->vga_misc.vga_input_stat1.val;
522 // Stunningly, reading stat1 is also a way to reset
523 // the state of attribute controller address/data flipflop
524 // That is some mighty fine crack the designers were smoking.
526 vga->vga_attribute_controller.state=ATTR_ADDR;
532 static int feature_control_read(struct guest_info *core,
538 struct vga_internal *vga = (struct vga_internal *) priv_data;
540 PrintDebug("vga: feature control read data=0x%x\n",
541 vga->vga_misc.vga_feature_control.val);
543 ERR_WRONG_SIZE("read","feature control",len,1,1);
545 *((uint8_t*)dest) = vga->vga_misc.vga_feature_control.val;
550 static int feature_control_write(struct guest_info *core,
556 struct vga_internal *vga = (struct vga_internal *) priv_data;
558 PrintDebug("vga: feature control (%s) write data=0x%x\n",
559 port==0x3ba ? "mono" : "color",
562 ERR_WRONG_SIZE("write","feature control",len,1,1);
564 vga->vga_misc.vga_feature_control.val = *((uint8_t*)src) ;
572 static int video_subsys_enable_read(struct guest_info *core,
578 struct vga_internal *vga = (struct vga_internal *) priv_data;
580 PrintDebug("vga: video subsys enable read data=0x%x\n",
581 vga->vga_misc.vga_video_subsys_enable.val);
583 ERR_WRONG_SIZE("read","video subsys enable",len,1,1);
585 *((uint8_t*)dest) = vga->vga_misc.vga_video_subsys_enable.val;
590 static int video_subsys_enable_write(struct guest_info *core,
596 struct vga_internal *vga = (struct vga_internal *) priv_data;
598 PrintDebug("vga: video subsys enable write data=0x%x\n", *((uint8_t*)src));
600 ERR_WRONG_SIZE("write","video subsys enable",len,1,1);
602 vga->vga_misc.vga_video_subsys_enable.val = *((uint8_t*)src) ;
609 static int sequencer_address_read(struct guest_info *core,
615 struct vga_internal *vga = (struct vga_internal *) priv_data;
617 PrintDebug("vga: sequencer address read data=0x%x\n",
618 vga->vga_sequencer.vga_sequencer_addr.val);
620 ERR_WRONG_SIZE("read","vga sequenver addr",len,1,1);
622 *((uint8_t*)dest) = vga->vga_sequencer.vga_sequencer_addr.val;
627 static int sequencer_address_write(struct guest_info *core,
633 struct vga_internal *vga = (struct vga_internal *) priv_data;
636 new_addr=*((uint8_t*)src);
638 PrintDebug("vga: sequencer address write data=0x%x\n", new_addr);
640 ERR_WRONG_SIZE("write","vga sequenver addr",len,1,1);
642 if (new_addr>VGA_SEQUENCER_NUM) {
643 PrintError("vga: ignoring change of sequencer address to %u (>%u)\n",
644 new_addr, VGA_SEQUENCER_NUM);
647 vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ;
653 static int sequencer_data_read(struct guest_info *core,
659 struct vga_internal *vga = (struct vga_internal *) priv_data;
663 index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
664 data=vga->vga_sequencer.vga_sequencer_regs[index];
666 PrintDebug("vga: sequencer data read data (index=%d) = 0x%x\n",
669 ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
671 *((uint8_t*)dest) = data;
676 static int sequencer_data_write(struct guest_info *core,
682 struct vga_internal *vga = (struct vga_internal *) priv_data;
686 data=*((uint8_t*)src);
687 index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
689 PrintDebug("vga: sequencer write data (index=%d) with 0x%x\n",
692 ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
694 vga->vga_sequencer.vga_sequencer_regs[index] = data;
704 static int crt_controller_address_read(struct guest_info *core,
710 struct vga_internal *vga = (struct vga_internal *) priv_data;
712 PrintDebug("vga: crt controller (%s) address read data=0x%x\n",
713 port==0x3b4 ? "mono" : "color",
714 vga->vga_crt_controller.vga_crt_addr.val);
716 ERR_WRONG_SIZE("read","vga crt controller addr",len,1,1);
718 *((uint8_t*)dest) = vga->vga_crt_controller.vga_crt_addr.val;
723 static int crt_controller_address_write(struct guest_info *core,
729 struct vga_internal *vga = (struct vga_internal *) priv_data;
732 new_addr=*((uint8_t*)src);
734 PrintDebug("vga: crt controller (%s) address write data=0x%x\n",
735 port==0x3b4 ? "mono" : "color",
738 ERR_WRONG_SIZE("write","vga crt controller addr",len,1,1);
740 if (new_addr>VGA_CRT_CONTROLLER_NUM) {
741 PrintError("vga: ignoring change of crt controller address to %u (>%u)\n",
742 new_addr, VGA_CRT_CONTROLLER_NUM);
745 vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ;
751 static int crt_controller_data_read(struct guest_info *core,
757 struct vga_internal *vga = (struct vga_internal *) priv_data;
761 index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
762 data=vga->vga_crt_controller.vga_crt_controller_regs[index];
764 PrintDebug("vga: crt controller data (%s) read data (index=%d) = 0x%x\n",
765 port==0x3b5 ? "mono" : "color",
768 ERR_WRONG_SIZE("read","vga crt controller data",len,1,1);
770 *((uint8_t*)dest) = data;
775 static int crt_controller_data_write(struct guest_info *core,
781 struct vga_internal *vga = (struct vga_internal *) priv_data;
785 data=*((uint8_t*)src);
787 index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
789 PrintDebug("vga: crt controller (%s) write data (index=%d) with 0x%x\n",
790 port==0x3b5 ? "mono" : "color",
793 ERR_WRONG_SIZE("read","vga crt controlle data",len,1,1);
795 vga->vga_crt_controller.vga_crt_controller_regs[index] = data;
803 static int graphics_controller_address_read(struct guest_info *core,
809 struct vga_internal *vga = (struct vga_internal *) priv_data;
811 PrintDebug("vga: graphics controller address read data=0x%x\n",
812 vga->vga_graphics_controller.vga_graphics_ctrl_addr.val);
814 ERR_WRONG_SIZE("read","vga graphics controller addr",len,1,1);
816 *((uint8_t*)dest) = vga->vga_graphics_controller.vga_graphics_ctrl_addr.val;
821 static int graphics_controller_address_write(struct guest_info *core,
827 struct vga_internal *vga = (struct vga_internal *) priv_data;
830 new_addr=*((uint8_t*)src);
832 PrintDebug("vga: graphics controller address write data=0x%x\n", new_addr);
834 ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,1);
836 if (new_addr>VGA_GRAPHICS_CONTROLLER_NUM) {
837 PrintError("vga: ignoring change of graphics controller address to %u (>%u)\n",
838 new_addr, VGA_GRAPHICS_CONTROLLER_NUM);
841 vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ;
847 static int graphics_controller_data_read(struct guest_info *core,
853 struct vga_internal *vga = (struct vga_internal *) priv_data;
857 index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
858 data=vga->vga_graphics_controller.vga_graphics_controller_regs[index];
860 PrintDebug("vga: graphics controller data read data (index=%d) = 0x%x\n",
863 ERR_WRONG_SIZE("read","vga graphics controller data",len,1,1);
865 *((uint8_t*)dest) = data;
870 static int graphics_controller_data_write(struct guest_info *core,
876 struct vga_internal *vga = (struct vga_internal *) priv_data;
880 data=*((uint8_t*)src);
881 index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
883 PrintDebug("vga: graphics_controller write data (index=%d) with 0x%x\n",
886 ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
888 vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data;
897 /* Note that these guys have a bizarre protocol*/
899 static int attribute_controller_address_read(struct guest_info *core,
905 struct vga_internal *vga = (struct vga_internal *) priv_data;
907 PrintDebug("vga: attribute controller address read data=0x%x\n",
908 vga->vga_attribute_controller.vga_attribute_controller_addr.val);
910 ERR_WRONG_SIZE("read","vga attribute controller addr",len,1,1);
912 *((uint8_t*)dest) = vga->vga_attribute_controller.vga_attribute_controller_addr.val;
914 // Reading the attribute controller does not change the state
919 static int attribute_controller_address_and_data_write(struct guest_info *core,
925 struct vga_internal *vga = (struct vga_internal *) priv_data;
928 if (vga->vga_attribute_controller.state==ATTR_ADDR) {
929 uint8_t new_addr = *((uint8_t*)src);
930 // We are to treat this as an address write, and flip state
931 // to expect data ON THIS SAME PORT
932 PrintDebug("vga: graphics controller address write data=0x%x\n", new_addr);
934 ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,1);
936 if (new_addr>VGA_ATTRIBUTE_CONTROLLER_NUM) {
937 PrintError("vga: ignoring change of attribute controller address to %u (>%u)\n",
938 new_addr, VGA_ATTRIBUTE_CONTROLLER_NUM);
941 vga->vga_attribute_controller.vga_attribute_controller_addr.val = *((uint8_t*)src) ;
943 vga->vga_attribute_controller.state=ATTR_DATA;
946 } else if (vga->vga_attribute_controller.state==ATTR_DATA) {
948 uint8_t data = *((uint8_t*)src);
949 uint8_t index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
951 PrintDebug("vga: graphics controller data write index %d with data=0x%x\n", index,data);
953 ERR_WRONG_SIZE("write","vga graphics controller data",len,1,1);
955 vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data;
957 vga->vga_attribute_controller.state=ATTR_ADDR;
966 static int attribute_controller_data_read(struct guest_info *core,
972 struct vga_internal *vga = (struct vga_internal *) priv_data;
976 index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
977 data=vga->vga_attribute_controller.vga_attribute_controller_regs[index];
979 PrintDebug("vga: attribute controller data read data (index=%d) = 0x%x\n",
982 ERR_WRONG_SIZE("read","vga attribute controller data",len,1,1);
984 *((uint8_t*)dest) = data;
991 Note that these guys also have a strange protocol
992 since they need to squeeze 18 bits of data through
995 static int dac_write_address_read(struct guest_info *core,
1001 struct vga_internal *vga = (struct vga_internal *) priv_data;
1003 PrintDebug("vga: dac write address read data=0x%x\n",
1004 vga->vga_dac.vga_dac_write_addr);
1006 ERR_WRONG_SIZE("read","vga dac write addr",len,1,1);
1008 *((uint8_t*)dest) = vga->vga_dac.vga_dac_write_addr;
1010 // This read does not reset the state machine
1015 static int dac_write_address_write(struct guest_info *core,
1021 struct vga_internal *vga = (struct vga_internal *) priv_data;
1024 new_addr=*((uint8_t*)src);
1026 PrintDebug("vga: dac write address write data=0x%x\n", new_addr);
1028 ERR_WRONG_SIZE("write","vga dac write addr",len,1,1);
1030 // cannot be out of bounds since there are 256 regs
1032 vga->vga_dac.vga_dac_write_addr = *((uint8_t*)src) ;
1034 // Now we also need to reset the state machine
1036 vga->vga_dac.state=DAC_WRITE;
1037 vga->vga_dac.channel=RED;
1043 static int dac_read_address_read(struct guest_info *core,
1049 struct vga_internal *vga = (struct vga_internal *) priv_data;
1051 PrintDebug("vga: dac read address read data=0x%x\n",
1052 vga->vga_dac.vga_dac_read_addr);
1054 ERR_WRONG_SIZE("read","vga dac read addr",len,1,1);
1056 *((uint8_t*)dest) = vga->vga_dac.vga_dac_read_addr;
1058 // This read does not reset the state machine
1063 static int dac_read_address_write(struct guest_info *core,
1069 struct vga_internal *vga = (struct vga_internal *) priv_data;
1072 new_addr=*((uint8_t*)src);
1074 PrintDebug("vga: dac read address write data=0x%x\n", new_addr);
1076 ERR_WRONG_SIZE("write","vga dac read addr",len,1,1);
1078 // cannot be out of bounds since there are 256 regs
1080 vga->vga_dac.vga_dac_read_addr = *((uint8_t*)src) ;
1082 // Now we also need to reset the state machine
1084 vga->vga_dac.state=DAC_READ;
1085 vga->vga_dac.channel=RED;
1091 static int dac_data_read(struct guest_info *core,
1097 struct vga_internal *vga = (struct vga_internal *) priv_data;
1102 if (vga->vga_dac.state!=DAC_READ) {
1103 PrintError("vga: dac data read while in other state\n");
1104 // results undefined, so we continue
1107 ERR_WRONG_SIZE("read","vga dac read data",len,1,1);
1109 curreg = vga->vga_dac.vga_dac_read_addr;
1110 curchannel = vga->vga_dac.channel;
1111 data = (vga->vga_dac.vga_dac_palette[curreg] >> curchannel*8) & 0x3f;
1113 PrintDebug("vga: dac reg %u [%s] = 0x%x\n",
1115 curchannel == 0 ? "RED" : curchannel == 1 ? "GREEN"
1116 : curchannel==2 ? "BLUE" : "BAD CHANNEL",
1119 *((uint8_t*)dest) = data;
1121 curchannel = (curchannel+1)%3;
1122 vga->vga_dac.channel=curchannel;
1123 if (curchannel==0) {
1124 curreg = (curreg + 1) % VGA_DAC_NUM_ENTRIES;
1126 vga->vga_dac.vga_dac_read_addr = curreg;
1127 vga->vga_dac.state=DAC_READ;
1134 static int dac_data_write(struct guest_info *core,
1140 struct vga_internal *vga = (struct vga_internal *) priv_data;
1144 vga_palette_reg data32;
1145 vga_palette_reg mask32;
1147 if (vga->vga_dac.state!=DAC_WRITE) {
1148 PrintError("vga: dac data write while in other state\n");
1149 // results undefined, so we continue
1152 ERR_WRONG_SIZE("read","vga dac write data",len,1,1);
1154 curreg = vga->vga_dac.vga_dac_write_addr;
1155 curchannel = vga->vga_dac.channel;
1156 data = *((uint8_t *)src);
1158 PrintDebug("vga: dac reg %u [%s] write with 0x%x\n",
1160 curchannel == 0 ? "RED" : curchannel == 1 ? "GREEN"
1161 : curchannel==2 ? "BLUE" : "BAD CHANNEL",
1164 data32 = data & 0x3f ;
1165 data32 <<= curchannel*8;
1166 mask32 = ~(0xff << (curchannel * 8));
1168 vga->vga_dac.vga_dac_palette[curreg] &= mask32;
1169 vga->vga_dac.vga_dac_palette[curreg] |= data32;
1171 curchannel = (curchannel+1)%3;
1172 vga->vga_dac.channel=curchannel;
1173 if (curchannel==0) {
1174 curreg = (curreg + 1) % VGA_DAC_NUM_ENTRIES;
1176 vga->vga_dac.vga_dac_write_addr = curreg;
1177 vga->vga_dac.state=DAC_WRITE;
1186 static int dac_pixel_mask_read(struct guest_info *core,
1192 struct vga_internal *vga = (struct vga_internal *) priv_data;
1194 PrintDebug("vga: dac pixel mask read data=0x%x\n",
1195 vga->vga_dac.vga_pixel_mask);
1197 ERR_WRONG_SIZE("read","vga pixel mask",len,1,1);
1199 *((uint8_t*)dest) = vga->vga_dac.vga_pixel_mask;
1204 static int dac_pixel_mask_write(struct guest_info *core,
1210 struct vga_internal *vga = (struct vga_internal *) priv_data;
1213 new_data=*((uint8_t*)src);
1215 PrintDebug("vga: dac pixel mask write data=0x%x\n", new_data);
1217 ERR_WRONG_SIZE("write","pixel mask",len,1,1);
1219 vga->vga_dac.vga_pixel_mask = new_data;
1224 static int init_vga(struct vga_internal *vga)
1226 // TODO: startup spec of register contents, if any
1227 PrintError("vga: init_vga is UNIMPLEMTED\n");
1231 static int free_vga(struct vga_internal *vga)
1235 struct vm_device *dev = vga->dev;
1237 // Framebuffer deletion is user's responsibility
1239 // if (vga->mem_store) {
1240 // V3_FreePages(v3_hva_to_hpa(vga->mem_store),MEM_REGION_NUM_PAGES);
1241 // vga->mem_store=0;
1244 for (i=0;i<MAP_NUM;i++) {
1246 V3_FreePages(V3_PAddr(vga->map[i]),MAP_SIZE/4096);
1251 v3_unhook_mem(vga->dev->vm, V3_MEM_CORE_ANY, MEM_REGION_START);
1255 ret |= v3_dev_unhook_io(dev, VGA_MISC_OUT_READ);
1256 // The following also covers VGA_INPUT_STAT0_READ
1257 ret |= v3_dev_unhook_io(dev, VGA_MISC_OUT_WRITE);
1258 // The following also covers VGA_FEATURE_CTRL_WRITE_MONO
1259 ret |= v3_dev_unhook_io(dev, VGA_INPUT_STAT1_READ_MONO);
1260 // The folowinn also covers VGA FEATURE_CONTROL_WRITE_COLOR
1261 ret |= v3_dev_unhook_io(dev, VGA_INPUT_STAT1_READ_COLOR);
1262 ret |= v3_dev_unhook_io(dev, VGA_FEATURE_CONTROL_READ);
1264 ret |= v3_dev_unhook_io(dev, VGA_VIDEO_SUBSYS_ENABLE);
1266 /* Sequencer registers */
1267 ret |= v3_dev_unhook_io(dev, VGA_SEQUENCER_ADDRESS);
1268 ret |= v3_dev_unhook_io(dev, VGA_SEQUENCER_DATA);
1270 /* CRT controller registers */
1271 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_MONO);
1272 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_COLOR);
1273 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_DATA_MONO);
1274 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_DATA_COLOR);
1276 /* graphics controller registers */
1277 ret |= v3_dev_unhook_io(dev, VGA_GRAPHICS_CONTROLLER_ADDRESS);
1278 ret |= v3_dev_unhook_io(dev, VGA_GRAPHICS_CONTROLLER_DATA);
1280 /* attribute controller registers */
1281 ret |= v3_dev_unhook_io(dev, VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE);
1282 ret |= v3_dev_unhook_io(dev, VGA_ATTRIBUTE_CONTROLLER_READ);
1284 /* video DAC palette registers */
1285 ret |= v3_dev_unhook_io(dev, VGA_DAC_WRITE_ADDR);
1286 ret |= v3_dev_unhook_io(dev, VGA_DAC_READ_ADDR);
1287 ret |= v3_dev_unhook_io(dev, VGA_DAC_DATA);
1288 ret |= v3_dev_unhook_io(dev, VGA_DAC_PIXEL_MASK);
1296 static struct v3_device_ops dev_ops = {
1297 .free = (int (*)(void *))free_vga,
1301 static int vga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1302 struct vga_internal *vga;
1306 char * dev_id = v3_cfg_val(cfg, "ID");
1308 // DETERMINE THE FRAMEBUFFER AND SET IT EARLY
1309 // FRAMEBUFFER IS SUPPLIED BY THE BACKEND
1311 PrintDebug("vga: init_device\n");
1313 vga = (struct vga_internal *)V3_Malloc(sizeof(struct vga_internal));
1316 PrintError("vga: cannot allocate\n");
1320 memset(vga, 0, sizeof(struct vga_internal));
1322 // No memory store is allocated since we will use a full memory hook
1323 // The VGA maps can be read as well as written
1325 // Now allocate the maps
1326 for (i=0;i<MAP_NUM;i++) {
1327 vga->map[i] = (vga_map) V3_VAddr((void*)V3_AllocPages(MAP_SIZE/4096));
1328 if (!(vga->map[i])) {
1331 memset(vga->map[i],0,MAP_SIZE);
1334 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, vga);
1337 PrintError("Could not attach device %s\n", dev_id);
1344 if (v3_hook_full_mem(vm, V3_MEM_CORE_ANY,
1345 MEM_REGION_START, MEM_REGION_END,
1349 PrintError("vga: memory book failed\n");
1350 v3_remove_device(dev);
1356 /* Miscelaneous registers */
1357 ret |= v3_dev_hook_io(dev, VGA_MISC_OUT_READ, &misc_out_read, NULL);
1358 // The following also covers VGA_INPUT_STAT0_READ
1359 ret |= v3_dev_hook_io(dev, VGA_MISC_OUT_WRITE, &input_stat0_read, &misc_out_write);
1360 // The following also covers VGA_FEATURE_CTRL_WRITE_MONO
1361 ret |= v3_dev_hook_io(dev, VGA_INPUT_STAT1_READ_MONO, &input_stat1_read, &feature_control_write);
1362 // The folowinn also covers VGA FEATURE_CONTROL_WRITE_COLOR
1363 ret |= v3_dev_hook_io(dev, VGA_INPUT_STAT1_READ_COLOR, &input_stat1_read, &feature_control_write);
1364 ret |= v3_dev_hook_io(dev, VGA_FEATURE_CONTROL_READ, &feature_control_read, NULL);
1366 ret |= v3_dev_hook_io(dev, VGA_VIDEO_SUBSYS_ENABLE, &video_subsys_enable_read, &video_subsys_enable_write);
1368 /* Sequencer registers */
1369 ret |= v3_dev_hook_io(dev, VGA_SEQUENCER_ADDRESS, &sequencer_address_read, &sequencer_address_write);
1370 ret |= v3_dev_hook_io(dev, VGA_SEQUENCER_DATA, &sequencer_data_read, &sequencer_data_write);
1372 /* CRT controller registers */
1373 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_MONO, &crt_controller_address_read,&crt_controller_address_write);
1374 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_COLOR, &crt_controller_address_read,&crt_controller_address_write);
1375 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_DATA_MONO, &crt_controller_data_read,&crt_controller_data_write);
1376 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_DATA_COLOR, &crt_controller_data_read,&crt_controller_data_write);
1378 /* graphics controller registers */
1379 ret |= v3_dev_hook_io(dev, VGA_GRAPHICS_CONTROLLER_ADDRESS, &graphics_controller_address_read,&graphics_controller_address_write);
1380 ret |= v3_dev_hook_io(dev, VGA_GRAPHICS_CONTROLLER_DATA, &graphics_controller_data_read,&graphics_controller_data_write);
1382 /* attribute controller registers */
1383 ret |= v3_dev_hook_io(dev, VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE, &attribute_controller_address_read,&attribute_controller_address_and_data_write);
1384 ret |= v3_dev_hook_io(dev, VGA_ATTRIBUTE_CONTROLLER_READ, &attribute_controller_data_read,NULL);
1386 /* video DAC palette registers */
1387 ret |= v3_dev_hook_io(dev, VGA_DAC_WRITE_ADDR, &dac_write_address_read,&dac_write_address_write);
1388 ret |= v3_dev_hook_io(dev, VGA_DAC_READ_ADDR, &dac_read_address_read,&dac_read_address_write);
1389 ret |= v3_dev_hook_io(dev, VGA_DAC_DATA, &dac_data_read, &dac_data_write);
1390 ret |= v3_dev_hook_io(dev, VGA_DAC_PIXEL_MASK, &dac_pixel_mask_read, &dac_pixel_mask_write);
1393 PrintError("vga: Error allocating VGA I/O ports\n");
1394 v3_remove_device(dev);
1400 PrintDebug("vga: successfully added and initialized, waiting for framebuffer attach\n");
1406 device_register("VGA", vga_init);