#define MAP_SIZE 65536
#define MAP_NUM 4
+#define UPDATES_PER_RENDER 100
+
typedef uint8_t *vga_map; // points to MAP_SIZE data
+/* HACK HACK HACK */
+
+struct fb_info {
+ uint32_t rows;
+ uint32_t cols;
+ uint32_t bitsperpixel;
+};
+
+struct fb {
+ struct fb_info *info;
+ uint8_t * data;
+};
+
+//extern
+struct fb *palacios_linux_fb_hack_pointer;
+
+/* HACK HACK HACK */
+
#define VGA_MISC_OUT_READ 0x3cc
#define VGA_MISC_OUT_WRITE 0x3c2
#define VGA_DAC_WRITE_ADDR 0x3c8
#define VGA_DAC_READ_ADDR 0x3c7
-#define VGA_DAC_DATA 0x3c8
+#define VGA_DAC_DATA 0x3c9
#define VGA_DAC_PIXEL_MASK 0x3c6
#define VGA_DAC_NUM_ENTRIES 256
/* Index 6 */
struct vga_misc_reg vga_misc;
/* Index 7 */
- struct vga_color_dont_care__reg vga_color_dont_care;
+ struct vga_color_dont_care_reg vga_color_dont_care;
/* Index 8 */
vga_bit_mask_reg vga_bit_mask;
} __attribute__((packed));
struct vga_internal {
struct vm_device *dev;
+
+ bool passthrough;
+ bool skip_next_passthrough_out; // for word access
+
+ uint32_t updates_since_render;
struct frame_buf *framebuf; // we render to this
vga_map map[MAP_NUM]; // the maps that the host writes to
+ uint8_t latch[MAP_NUM]; // written to in any read, used during writes
+
/* Range of I/O ports here for backward compat with MDA and CGA */
struct vga_misc_regs vga_misc;
+static int render(struct vga_internal *vga)
+{
+ vga->updates_since_render++;
+
+ if (vga->updates_since_render<UPDATES_PER_RENDER) {
+ return 0;
+ }
+
+ // PrintError("vga: render UNIMPLEMENTED\n");
+
+ vga->updates_since_render=0;
+
+ if (!palacios_linux_fb_hack_pointer) {
+ return 0;
+ }
+
+
+
+
+ return 0;
+}
+
+
+static void get_mem_region(struct vga_internal *vga, uint64_t *mem_start, uint64_t *mem_end)
+{
+ switch (vga->vga_graphics_controller.vga_misc.memory_map) {
+ case 0:
+ *mem_start=0xa0000;
+ *mem_end=0xc0000;
+ break;
+ case 1:
+ *mem_start=0xa0000;
+ *mem_end=0xb0000;
+ break;
+ case 2:
+ *mem_start=0xb0000;
+ *mem_end=0xb8000;
+ break;
+ case 3:
+ *mem_start=0xb8000;
+ *mem_end=0xc0000;
+ break;
+ }
+}
+
+static uint64_t find_offset(struct vga_internal *vga, addr_t guest_addr)
+{
+ uint64_t mem_start, mem_end;
+
+ mem_start=mem_end=0;
+
+ get_mem_region(vga, &mem_start, &mem_end);
+
+ return (guest_addr-mem_start) % (mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start));
+
+}
+
+
+
+
static int vga_write(struct guest_info * core,
addr_t guest_addr,
void * src,
uint_t length,
void * priv_data)
{
+ int i;
+ struct vm_device *dev = (struct vm_device *)priv_data;
+ struct vga_internal *vga = (struct vga_internal *) dev->private_data;
+
+ PrintDebug("vga: memory write: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
+ if (vga->passthrough) {
+ PrintDebug("vga: passthrough write to 0x%p\n", V3_VAddr((void*)guest_addr));
+ memcpy(V3_VAddr((void*)guest_addr),src,length);
+ }
+
+ PrintDebug("vga: data written was \"");
+ for (i=0;i<length;i++) {
+ char c= ((char*)src)[i];
+ PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.');
+ }
+ PrintDebug("\"\n");
+
+ /* Write mode determine by Graphics Mode Register (Index 05h).writemode */
+
+ switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) {
+ case 0: {
+
+ /*
+ 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.
+ */
+
+ int i;
+
+ uint8_t mapnum;
+ uint64_t offset;
+
+ uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
+ uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
+
+ offset = find_offset(vga, guest_addr);
+
+ PrintDebug("vga: mode 0 write, offset=0x%llx, ror=%u, func=%u\n", offset,ror,func);
+
+ for (i=0;i<length;i++,offset++) {
+ // now for each map
+ uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
+ uint8_t esr = vga->vga_graphics_controller.vga_enable_set_reset.val &0xf;
+ uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
+ uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+
+ for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) {
+ vga_map map = vga->map[mapnum];
+ uint8_t data = ((uint8_t *)src)[i];
+ uint8_t latchval = vga->latch[mapnum];
+
+ // rotate data right
+ data = (data>>ror) | data<<(8-ror);
+
+ // use SR bit if ESR is on for this map
+ if (esr & 0x1) {
+ data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7); // expand sr bit
+ }
+
+ // Apply function
+ switch (func) {
+ case 0: // NOP
+ break;
+ case 1: // AND
+ data &= latchval;
+ break;
+ case 2: // OR
+ data |= latchval;
+ break;
+ case 3: // XOR
+ data ^= latchval;
+ break;
+ }
+
+ // mux between latch and alu output
+ if (bm & 0x1) {
+ // use alu output, which is in data
+ } else {
+ // use latch value
+ data=latchval;
+ }
+
+ // selective write
+ if (mm & 0x1) {
+ // write to this map
+ //PrintDebug("vga: write map %u offset 0x%p map=0x%p pointer=0x%p\n",mapnum,(void*)offset,map,&(map[offset]));
+ map[offset] = data;
+ } else {
+ // skip this map
+ }
+ }
+ }
+ }
+ break;
+
+
+
+ case 1: {
+ /*
+ 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.
+ */
+
+ int i;
+
+ uint64_t offset = find_offset(vga,guest_addr);
+
+ PrintDebug("vga: mode 1 write, offset=0x%llx\n", offset);
+
+ for (i=0;i<length;i++,offset++) {
+
+ uint8_t mapnum;
+ uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+
+ for (mapnum=0;mapnum<4;mapnum++, mm>>=1) {
+ vga_map map = vga->map[mapnum];
+ uint8_t latchval = vga->latch[mapnum];
+
+ // selective write
+ if (mm & 0x1) {
+ // write to this map
+ map[offset] = latchval;
+ } else {
+ // skip this map
+ }
+ }
+ }
+ }
+ break;
+
+ case 2: {
+ /*
+ 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.
+ */
+ int i;
+ uint8_t mapnum;
+ uint64_t offset;
+
+ uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
+
+ offset = find_offset(vga, guest_addr);
+
+ PrintDebug("vga: mode 2 write, offset=0x%llx, func=%u\n", offset,func);
+
+ for (i=0;i<length;i++,offset++) {
+ // now for each map
+ uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
+ uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+
+ for (mapnum=0;mapnum<4;mapnum++, bm>>=1, mm>>=1) {
+ vga_map map = vga->map[mapnum];
+ uint8_t data = ((uint8_t *)src)[i];
+ uint8_t latchval = vga->latch[mapnum];
+
+ // expand relevant bit to 8 bit
+ // it's basically esr=1, sr=bit from write
+ data = (uint8_t)(((sint8_t)(((data>>mapnum)&0x1)<<7))>>7);
+
+ // Apply function
+ switch (func) {
+ case 0: // NOP
+ break;
+ case 1: // AND
+ data &= latchval;
+ break;
+ case 2: // OR
+ data |= latchval;
+ break;
+ case 3: // XOR
+ data ^= latchval;
+ break;
+ }
+
+ // mux between latch and alu output
+ if (bm & 0x1) {
+ // use alu output, which is in data
+ } else {
+ // use latch value
+ data=latchval;
+ }
+
+ // selective write
+ if (mm & 0x1) {
+ // write to this map
+ map[offset] = data;
+ } else {
+ // skip this map
+ }
+ }
+ }
+ }
+ break;
+
+ case 3: {
+ /* 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.
+ */
+ int i;
+
+ uint8_t mapnum;
+ uint64_t offset;
+
+ uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
+
+ offset = find_offset(vga, guest_addr);
+
+ PrintDebug("vga: mode 3 write, offset=0x%llx, ror=%u\n", offset,ror);
+
+ for (i=0;i<length;i++,offset++) {
+ // now for each map
+ uint8_t data = ((uint8_t *)src)[i];
+
+ data = (data>>ror) | data<<(8-ror);
+
+ uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data;
+ uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
+ uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+
+ for (mapnum=0;mapnum<4;mapnum++, sr>>=1, bm>>=1, mm>>=1) {
+ vga_map map = vga->map[mapnum];
+ uint8_t latchval = vga->latch[mapnum];
+
+ data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7); // expand sr bit
+
+
+ // mux between latch and alu output
+ if (bm & 0x1) {
+ // use alu output, which is in data
+ } else {
+ // use latch value
+ data=latchval;
+ }
+
+ // selective write
+ if (mm & 0x1) {
+ // write to this map
+ map[offset] = data;
+ } else {
+ // skip this map
+ }
+ }
+ }
+
+ }
+ break;
+
+ // There is no default
+ }
+
+ render(vga);
+
+ return length;
+}
- PrintError("vga: vga_write UNIMPLEMENTED\n");
/*
-up to 256K mapped through a window of 128K
+up to 256K mapped through a window of 32 to 128K
most cards support linear mode as well
Memory model: 64K 32 bit locations; divided into 4 64K bit planes
-Write Modes - set via Graphics Mode Register (Index 05h).writemode
-
-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.
-
-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.
-
-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.
-
-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.
-
-five stages of a write:
-
-write(void *adx, uint8_t x) // or 4 byte?!
-
-uint8_t rx[4];
-
-switch (Write Mode) {
-case 0:
-// 1. Rotate
- x = ROR(x,Rotate Count)
-
-// 2. Clone from Host Data or Set/Reset Reg
- for (i=0;i<4;i++) {
- if (Enable Set/Reset[i]) {
- rx[i]=Set/Reset (expanded to 8 bits)
- } else {
- rx[i]=x;
- }
- }
-
-// 3. Logical Operator
- for (i=0;i<4;i++) {
- rx[i] = rx[i] LOP LATCH_REG[i]
-// LOP = NOP, AND, OR, XOR
- }
-
-// 4. Select
- for (i=0;i<4;i++) {
- rx[i] = BITWISE_MUX(rx[i], LATCH_REG[i], Bit Mask Reg);
- }
-
-// 5. Selective Write
- for (i=0;i<4;i++) {
- if (Map Mask Reg.Memory Plane Write Enable[i])
- BUF[TRANSLATE(adx,i)] = rx[i];
- }
-break;
-
-case 1:
-// 4. Select latch register directly
- for (i=0;i<4;i++) {
- rx[i] = LATCH_REG[i];
- }
-// 5. Selective Write
- for (i=0;i<4;i++) {
- if (Map Mask Reg.Memory Plane Write Enable[i])
- BUF[TRANSLATE(adx,i)] = rx[i];
- }
-
-
Assume linear framebuffer, starting at address buf:
*/
- return -1;
-}
+
static int vga_read(struct guest_info * core,
uint_t length,
void * priv_data)
{
+ int i;
+ struct vm_device *dev = (struct vm_device *)priv_data;
+ struct vga_internal *vga = (struct vga_internal *) dev->private_data;
+
- PrintError("vga: vga_read UNIMPLEMENTED\n");
+ PrintDebug("vga: memory read: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
+
+
+
/*
Reading, 2 modes, set via Graphics Mode Register (index 05h).Read Mode:
- 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))
- 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)
*/
-
- return -1;
-}
+ switch (vga->vga_graphics_controller.vga_graphics_mode.read_mode) {
+ case 0: {
+ /* 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)) */
+ uint8_t mapnum;
+ uint64_t offset;
+
+ mapnum = vga->vga_graphics_controller.vga_read_map_select.map_select;
+ offset = find_offset(vga,guest_addr);
+
+ if (offset>=65536) {
+ PrintError("vga: read to offset=%llu map=%u (%u bytes)\n",offset,mapnum,length);
+ }
+
+ memcpy(dst,(vga->map[mapnum])+offset,length);
+
+ // load the latches with the last item read
+ for (mapnum=0;mapnum<4;mapnum++) {
+ vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
+ }
+
+
+ }
+ break;
+ case 1: {
+ /* 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
+
+ Ref color is *4* bits, and thus a one byte read returns a comparison
+ with 8 pixels
+
+ */
+ int i;
+
+ uint8_t cc=vga->vga_graphics_controller.vga_color_compare.val & 0xf ;
+ uint8_t dc=vga->vga_graphics_controller.vga_color_dont_care.val & 0xf;
+
+ uint8_t mapnum;
+ uint64_t offset;
+ uint8_t byte;
+ uint8_t bits;
+
+ offset = find_offset(vga,guest_addr);
+
+ for (i=0;i<length;i++,offset++) {
+ vga_map map;
+ byte=0;
+ for (mapnum=0;mapnum<4;mapnum++) {
+ map = vga->map[mapnum];
+ if ( (dc>>mapnum)&0x1 ) { // don't care
+ bits=0;
+ } else {
+ // lower 4 bits
+ bits = (map[offset]&0xf) == cc;
+ bits <<= 1;
+ // upper 4 bits
+ bits |= (((map[offset]>>4))&0xf) == cc;
+ }
+ // not clear whether it is 0..k or k..0
+ byte<<=2;
+ byte|=bits;
+ }
+ }
+
+ // load the latches with the last item read
+ for (mapnum=0;mapnum<4;mapnum++) {
+ vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
+ }
+ }
+ break;
+ // there is no default
+ }
+ if (vga->passthrough) {
+ PrintDebug("vga: passthrough read from 0x%p\n",V3_VAddr((void*)guest_addr));
+ memcpy(dst,V3_VAddr((void*)guest_addr),length);
+ }
+
+
+ PrintDebug("vga: data read is \"");
+ for (i=0;i<length;i++) {
+ char c= ((char*)dst)[i];
+ PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.');
+ }
+ PrintDebug("\"\n");
+
+ return length;
-static int render(struct vga_internal *vga)
-{
- PrintError("vga: render UNIMPLEMENTED\n");
- return 0;
}
+
+
+
#define ERR_WRONG_SIZE(op,reg,len,min,max) \
if (((len)<(min)) || ((len)>(max))) { \
PrintError("vga: %s of %s wrong size (%d bytes, but only %d to %d allowed)\n",(op),(reg),(len),(min),(max)); \
return -1; \
}
+static inline void passthrough_io_in(uint16_t port, void * dest, uint_t length) {
+ switch (length) {
+ case 1:
+ *(uint8_t *)dest = v3_inb(port);
+ break;
+ case 2:
+ *(uint16_t *)dest = v3_inw(port);
+ break;
+ case 4:
+ *(uint32_t *)dest = v3_indw(port);
+ break;
+ default:
+ PrintError("vga: unsupported passthrough io in size %u\n",length);
+ break;
+ }
+}
+
+
+static inline void passthrough_io_out(uint16_t port, const void * src, uint_t length) {
+ switch (length) {
+ case 1:
+ v3_outb(port, *(uint8_t *)src);
+ break;
+ case 2:
+ v3_outw(port, *(uint16_t *)src);
+ break;
+ case 4:
+ v3_outdw(port, *(uint32_t *)src);
+ break;
+ default:
+ PrintError("vga: unsupported passthrough io out size %u\n",length);
+ break;
+ }
+}
+
+#define PASSTHROUGH_IO_IN(vga,port,dest,len) \
+ do { if ((vga)->passthrough) { passthrough_io_in(port,dest,len); } } while (0)
+#define PASSTHROUGH_IO_OUT(vga,port,src,len) \
+ do { if ((vga)->passthrough && (!(vga)->skip_next_passthrough_out)) { passthrough_io_out(port,src,len); } (vga)->skip_next_passthrough_out=false; } while (0)
+
+#define PASSTHROUGH_IO_SKIP_NEXT_OUT(vga) \
+ do { if ((vga)->passthrough) { (vga)->skip_next_passthrough_out=true; } } while (0)
+
+#define PASSTHROUGH_READ_CHECK(vga,inter,pass) \
+ do { if ((vga)->passthrough) { if ((inter)!=(pass)) { PrintError("vga: passthrough error: passthrough value read is 0x%x, but internal value read is 0x%x\n",(pass),(inter)); } } } while (0)
static int misc_out_read(struct guest_info *core,
uint16_t port,
PrintDebug("vga: misc out read data=0x%x\n", vga->vga_misc.vga_misc_out.val);
ERR_WRONG_SIZE("read","misc out",len,1,1);
-
+
*((uint8_t*)dest) = vga->vga_misc.vga_misc_out.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_misc_out.val,*((uint8_t*)dest));
+
return len;
}
PrintDebug("vga: misc out write data=0x%x\n", *((uint8_t*)src));
ERR_WRONG_SIZE("write","misc out",len,1,1);
-
+
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
vga->vga_misc.vga_misc_out.val = *((uint8_t*)src) ;
render(vga);
PrintDebug("vga: input stat0 read data=0x%x\n", vga->vga_misc.vga_input_stat0.val);
- ERR_WRONG_SIZE("read","inpust stat0",len,1,1);
+ ERR_WRONG_SIZE("read","input stat0",len,1,1);
*((uint8_t*)dest) = vga->vga_misc.vga_input_stat0.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat0.val,*(uint8_t*)dest);
+
return len;
}
port==0x3ba ? "mono" : "color",
vga->vga_misc.vga_input_stat1.val);
- ERR_WRONG_SIZE("read","inpust stat1",len,1,1);
+ ERR_WRONG_SIZE("read","input stat1",len,1,1);
+
*((uint8_t*)dest) = vga->vga_misc.vga_input_stat1.val;
vga->vga_attribute_controller.state=ATTR_ADDR;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat1.val,*(uint8_t*)dest);
+
return len;
}
ERR_WRONG_SIZE("read","feature control",len,1,1);
+
*((uint8_t*)dest) = vga->vga_misc.vga_feature_control.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_feature_control.val,*(uint8_t*)dest);
+
return len;
}
ERR_WRONG_SIZE("write","feature control",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
vga->vga_misc.vga_feature_control.val = *((uint8_t*)src) ;
render(vga);
*((uint8_t*)dest) = vga->vga_misc.vga_video_subsys_enable.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_video_subsys_enable.val,*(uint8_t*)dest);
+
return len;
}
ERR_WRONG_SIZE("write","video subsys enable",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
vga->vga_misc.vga_video_subsys_enable.val = *((uint8_t*)src) ;
render(vga);
PrintDebug("vga: sequencer address read data=0x%x\n",
vga->vga_sequencer.vga_sequencer_addr.val);
- ERR_WRONG_SIZE("read","vga sequenver addr",len,1,1);
+ ERR_WRONG_SIZE("read","vga sequencer addr",len,1,1);
*((uint8_t*)dest) = vga->vga_sequencer.vga_sequencer_addr.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_sequencer.vga_sequencer_addr.val,*(uint8_t*)dest);
+
+ return len;
+}
+
+static int sequencer_data_write(struct guest_info *core,
+ uint16_t port,
+ void *src,
+ uint_t len,
+ void *priv_data)
+{
+ struct vga_internal *vga = (struct vga_internal *) priv_data;
+ uint8_t index;
+ uint8_t data;
+
+ data=*((uint8_t*)src);
+ index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
+
+ PrintDebug("vga: sequencer write data (index=%d) with 0x%x\n",
+ index, data);
+
+ ERR_WRONG_SIZE("write","vga sequencer data",len,1,1);
+
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+
+ if (index>=VGA_SEQUENCER_NUM) {
+ PrintError("vga: sequencer data write is for invalid index %d, ignoring\n",index);
+ } else {
+ vga->vga_sequencer.vga_sequencer_regs[index] = data;
+ }
+
+ render(vga);
+
return len;
}
new_addr=*((uint8_t*)src);
- PrintDebug("vga: sequencer address write data=0x%x\n", new_addr);
+ PrintDebug("vga: sequencer address write data=0x%x len=%u\n", len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
- ERR_WRONG_SIZE("write","vga sequenver addr",len,1,1);
+ ERR_WRONG_SIZE("write","vga sequencer addr",len,1,2);
- if (new_addr>VGA_SEQUENCER_NUM) {
- PrintError("vga: ignoring change of sequencer address to %u (>%u)\n",
- new_addr, VGA_SEQUENCER_NUM);
- //return -1;
- } else {
- vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ;
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ;
+
+ if (len==2) {
+ PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
+ // second byte is the data
+ if (sequencer_data_write(core,port,src+1,1,vga)!=1) {
+ PrintError("vga: write of data failed\n");
+ return -1;
+ }
}
return len;
uint8_t data;
index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
- data=vga->vga_sequencer.vga_sequencer_regs[index];
-
- PrintDebug("vga: sequencer data read data (index=%d) = 0x%x\n",
- index, data);
- ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
+ if (index>=VGA_SEQUENCER_NUM) {
+ data=0;
+ PrintError("vga: sequencer data read at invalid index %d, returning zero\n",index);
+ } else {
+ data=vga->vga_sequencer.vga_sequencer_regs[index];
+ }
+
+ PrintDebug("vga: sequencer data read data (index=%d) = 0x%x\n",
+ index, data);
+
+ ERR_WRONG_SIZE("read","vga sequencer data",len,1,1);
*((uint8_t*)dest) = data;
- return len;
-}
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
-static int sequencer_data_write(struct guest_info *core,
- uint16_t port,
- void *src,
- uint_t len,
- void *priv_data)
-{
- struct vga_internal *vga = (struct vga_internal *) priv_data;
- uint8_t index;
- uint8_t data;
-
- data=*((uint8_t*)src);
- index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
-
- PrintDebug("vga: sequencer write data (index=%d) with 0x%x\n",
- index, data);
-
- ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
-
- vga->vga_sequencer.vga_sequencer_regs[index] = data;
+ PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
- render(vga);
-
return len;
}
+
*((uint8_t*)dest) = vga->vga_crt_controller.vga_crt_addr.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_crt_controller.vga_crt_addr.val,*(uint8_t*)dest);
+
+ return len;
+}
+
+static int crt_controller_data_write(struct guest_info *core,
+ uint16_t port,
+ void *src,
+ uint_t len,
+ void *priv_data)
+{
+ struct vga_internal *vga = (struct vga_internal *) priv_data;
+ uint8_t index;
+ uint8_t data;
+
+ data=*((uint8_t*)src);
+
+ index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
+
+ PrintDebug("vga: crt controller (%s) write data (index=%d) with 0x%x\n",
+ port==0x3b5 ? "mono" : "color",
+ index, data);
+
+ ERR_WRONG_SIZE("write","vga crt controller data",len,1,1);
+
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ if (index>=VGA_CRT_CONTROLLER_NUM) {
+ PrintError("vga; crt controller write is for illegal index %d, ignoring\n",index);
+ } else {
+ vga->vga_crt_controller.vga_crt_controller_regs[index] = data;
+ }
+
+ render(vga);
+
return len;
}
new_addr=*((uint8_t*)src);
- PrintDebug("vga: crt controller (%s) address write data=0x%x\n",
+ PrintDebug("vga: crt controller (%s) address write data=0x%x len=%u\n",
port==0x3b4 ? "mono" : "color",
- new_addr);
+ len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
- ERR_WRONG_SIZE("write","vga crt controller addr",len,1,1);
+ ERR_WRONG_SIZE("write","vga crt controller addr",len,1,2);
- if (new_addr>VGA_CRT_CONTROLLER_NUM) {
- PrintError("vga: ignoring change of crt controller address to %u (>%u)\n",
- new_addr, VGA_CRT_CONTROLLER_NUM);
- //return -1;
- } else {
- vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ;
- }
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+ vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ;
+
+ if (len==2) {
+ PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
+ // second byte is the data
+ if (crt_controller_data_write(core,port,src+1,1,vga)!=1) {
+ PrintError("vga: write of data failed\n");
+ return -1;
+ }
+ }
+
return len;
}
uint8_t data;
index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
- data=vga->vga_crt_controller.vga_crt_controller_regs[index];
- PrintDebug("vga: crt controller data (%s) read data (index=%d) = 0x%x\n",
- port==0x3b5 ? "mono" : "color",
- index, data);
+ if (index>=VGA_CRT_CONTROLLER_NUM) {
+ data=0;
+ PrintError("vga: crt controller data read for illegal index %d, returning zero\n",index);
+ } else {
+ data=vga->vga_crt_controller.vga_crt_controller_regs[index];
+ }
+ PrintDebug("vga: crt controller data (index=%d) = 0x%x\n",index,data);
+
ERR_WRONG_SIZE("read","vga crt controller data",len,1,1);
*((uint8_t*)dest) = data;
- return len;
-}
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
-static int crt_controller_data_write(struct guest_info *core,
- uint16_t port,
- void *src,
- uint_t len,
- void *priv_data)
-{
- struct vga_internal *vga = (struct vga_internal *) priv_data;
- uint8_t index;
- uint8_t data;
-
- data=*((uint8_t*)src);
-
- index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
-
- PrintDebug("vga: crt controller (%s) write data (index=%d) with 0x%x\n",
- port==0x3b5 ? "mono" : "color",
- index, data);
-
- ERR_WRONG_SIZE("read","vga crt controlle data",len,1,1);
-
- vga->vga_crt_controller.vga_crt_controller_regs[index] = data;
-
- render(vga);
+ PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t *)dest);
return len;
}
+
static int graphics_controller_address_read(struct guest_info *core,
uint16_t port,
void *dest,
*((uint8_t*)dest) = vga->vga_graphics_controller.vga_graphics_ctrl_addr.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_graphics_controller.vga_graphics_ctrl_addr.val,*(uint8_t*)dest);
+
+ return len;
+}
+
+static int graphics_controller_data_write(struct guest_info *core,
+ uint16_t port,
+ void *src,
+ uint_t len,
+ void *priv_data)
+{
+ struct vga_internal *vga = (struct vga_internal *) priv_data;
+ uint8_t index;
+ uint8_t data;
+
+ data=*((uint8_t*)src);
+ index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
+
+
+ PrintDebug("vga: graphics_controller write data (index=%d) with 0x%x\n",
+ index, data);
+
+ ERR_WRONG_SIZE("write","vga graphics controller data",len,1,1);
+
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ if (index>=VGA_GRAPHICS_CONTROLLER_NUM) {
+ PrintError("vga: graphics controller write for illegal index %d ignored\n",index);
+ } else {
+ vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data;
+ }
+
+ render(vga);
+
return len;
}
new_addr=*((uint8_t*)src);
- PrintDebug("vga: graphics controller address write data=0x%x\n", new_addr);
+ PrintDebug("vga: graphics controller address write data=0x%x len=%u\n",
+ len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
- ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,1);
+ ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,2);
- if (new_addr>VGA_GRAPHICS_CONTROLLER_NUM) {
- PrintError("vga: ignoring change of graphics controller address to %u (>%u)\n",
- new_addr, VGA_GRAPHICS_CONTROLLER_NUM);
- //return -1;
- } else {
- vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ;
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ;
+
+ if (len==2) {
+ PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
+ // second byte is the data
+ if (graphics_controller_data_write(core,port,src+1,1,vga)!=1) {
+ PrintError("vga: write of data failed\n");
+ return -1;
+ }
}
return len;
uint8_t data;
index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
- data=vga->vga_graphics_controller.vga_graphics_controller_regs[index];
+
+
+ if (index>=VGA_GRAPHICS_CONTROLLER_NUM) {
+ data=0;
+ PrintError("vga: graphics controller data read from illegal index %d, returning zero\n",index);
+ } else {
+ data=vga->vga_graphics_controller.vga_graphics_controller_regs[index];
+ }
PrintDebug("vga: graphics controller data read data (index=%d) = 0x%x\n",
index, data);
*((uint8_t*)dest) = data;
- return len;
-}
-
-static int graphics_controller_data_write(struct guest_info *core,
- uint16_t port,
- void *src,
- uint_t len,
- void *priv_data)
-{
- struct vga_internal *vga = (struct vga_internal *) priv_data;
- uint8_t index;
- uint8_t data;
-
- data=*((uint8_t*)src);
- index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
-
- PrintDebug("vga: graphics_controller write data (index=%d) with 0x%x\n",
- index, data);
-
- ERR_WRONG_SIZE("read","vga sequenver data",len,1,1);
-
- vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
- render(vga);
+ PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
return len;
}
+
/* Note that these guys have a bizarre protocol*/
static int attribute_controller_address_read(struct guest_info *core,
*((uint8_t*)dest) = vga->vga_attribute_controller.vga_attribute_controller_addr.val;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_attribute_controller.vga_attribute_controller_addr.val,*(uint8_t*)dest);
+
// Reading the attribute controller does not change the state
return len;
uint8_t new_addr = *((uint8_t*)src);
// We are to treat this as an address write, and flip state
// to expect data ON THIS SAME PORT
- PrintDebug("vga: graphics controller address write data=0x%x\n", new_addr);
+ PrintDebug("vga: attribute controller address write data=0x%x\n", new_addr);
- ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,1);
+ ERR_WRONG_SIZE("write","vga attribute controller addr",len,1,1);
+
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ vga->vga_attribute_controller.vga_attribute_controller_addr.val = new_addr;
- if (new_addr>VGA_ATTRIBUTE_CONTROLLER_NUM) {
- PrintError("vga: ignoring change of attribute controller address to %u (>%u)\n",
- new_addr, VGA_ATTRIBUTE_CONTROLLER_NUM);
- //return -1;
- } else {
- vga->vga_attribute_controller.vga_attribute_controller_addr.val = *((uint8_t*)src) ;
- }
vga->vga_attribute_controller.state=ATTR_DATA;
return len;
uint8_t data = *((uint8_t*)src);
uint8_t index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
- PrintDebug("vga: graphics controller data write index %d with data=0x%x\n", index,data);
+ PrintDebug("vga: attribute controller data write index %d with data=0x%x\n", index,data);
- ERR_WRONG_SIZE("write","vga graphics controller data",len,1,1);
+ ERR_WRONG_SIZE("write","vga attribute controller data",len,1,1);
- vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data;
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
+ if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) {
+ PrintError("vga: attribute controller write to illegal index %d ignored\n",index);
+ } else {
+ vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data;
+ }
vga->vga_attribute_controller.state=ATTR_ADDR;
uint8_t data;
index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
- data=vga->vga_attribute_controller.vga_attribute_controller_regs[index];
+
+ if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) {
+ data=0;
+ PrintError("vga: attribute controller read of illegal index %d, returning zero\n",index);
+ } else {
+ data=vga->vga_attribute_controller.vga_attribute_controller_regs[index];
+ }
PrintDebug("vga: attribute controller data read data (index=%d) = 0x%x\n",
index, data);
*((uint8_t*)dest) = data;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
+
return len;
}
ERR_WRONG_SIZE("read","vga dac write addr",len,1,1);
+
*((uint8_t*)dest) = vga->vga_dac.vga_dac_write_addr;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_write_addr,*(uint8_t*)dest);
+
// This read does not reset the state machine
return len;
ERR_WRONG_SIZE("write","vga dac write addr",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
// cannot be out of bounds since there are 256 regs
vga->vga_dac.vga_dac_write_addr = *((uint8_t*)src) ;
*((uint8_t*)dest) = vga->vga_dac.vga_dac_read_addr;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_read_addr,*(uint8_t*)dest);
+
// This read does not reset the state machine
return len;
ERR_WRONG_SIZE("write","vga dac read addr",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
// cannot be out of bounds since there are 256 regs
vga->vga_dac.vga_dac_read_addr = *((uint8_t*)src) ;
data);
*((uint8_t*)dest) = data;
+
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
curchannel = (curchannel+1)%3;
vga->vga_dac.channel=curchannel;
ERR_WRONG_SIZE("read","vga dac write data",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
curreg = vga->vga_dac.vga_dac_write_addr;
curchannel = vga->vga_dac.channel;
data = *((uint8_t *)src);
*((uint8_t*)dest) = vga->vga_dac.vga_pixel_mask;
+ PASSTHROUGH_IO_IN(vga,port,dest,len);
+
+ PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_pixel_mask,*(uint8_t*)dest);
+
return len;
}
ERR_WRONG_SIZE("write","pixel mask",len,1,1);
+ PASSTHROUGH_IO_OUT(vga,port,src,len);
+
vga->vga_dac.vga_pixel_mask = new_data;
return len;
int ret;
char * dev_id = v3_cfg_val(cfg, "ID");
+ char * passthrough = v3_cfg_val(cfg, "passthrough");
// DETERMINE THE FRAMEBUFFER AND SET IT EARLY
// FRAMEBUFFER IS SUPPLIED BY THE BACKEND
memset(vga, 0, sizeof(struct vga_internal));
+ if (passthrough && strcasecmp(passthrough,"enable")==0) {
+ PrintDebug("vga: enabling passthrough\n");
+ vga->passthrough=true;
+ vga->skip_next_passthrough_out=false;
+ }
+
// No memory store is allocated since we will use a full memory hook
// The VGA maps can be read as well as written
+ // Reads also affect writes, since they are how you fill the latches
// Now allocate the maps
for (i=0;i<MAP_NUM;i++) {
vga->map[i] = (vga_map) V3_VAddr((void*)V3_AllocPages(MAP_SIZE/4096));
if (!(vga->map[i])) {
+ PrintError("vga: cannot allocate maps\n");
free_vga(vga);
+ return -1;
}
memset(vga->map[i],0,MAP_SIZE);
}