intindex;intscratch_size;uint32_t*scratch;intnew_width;intnew_height;uint32_tguest;uint32_tsvgaid;uint32_twred;uint32_twgreen;uint32_twblue;intsyncing;intfb_size;union{uint32_t*fifo;struct__attribute__((__packed__)){uint32_tmin;uint32_tmax;uint32_tnext_cmd;uint32_tstop;/* Add registers here when adding capabilities. */uint32_tfifo[0];}*cmd;};#defineREDRAW_FIFO_LEN512structvmsvga_rect_s{intx,y,w,h;}redraw_fifo[REDRAW_FIFO_LEN];intredraw_fifo_first,redraw_fifo_last;};structpci_vmsvga_state_s{PCIDevicecard;structvmsvga_state_schip;};#defineSVGA_MAGIC0x900000UL#defineSVGA_MAKE_ID(ver)(SVGA_MAGIC<<8|(ver))#defineSVGA_ID_0SVGA_MAKE_ID(0)#defineSVGA_ID_1SVGA_MAKE_ID(1)#defineSVGA_ID_2SVGA_MAKE_ID(2)#defineSVGA_LEGACY_BASE_PORT0x4560#defineSVGA_INDEX_PORT0x0#defineSVGA_VALUE_PORT0x1#defineSVGA_BIOS_PORT0x2#defineSVGA_VERSION_2#ifdefSVGA_VERSION_2#defineSVGA_IDSVGA_ID_2#defineSVGA_IO_BASESVGA_LEGACY_BASE_PORT#defineSVGA_IO_MUL1#defineSVGA_FIFO_SIZE0x10000
#defineSVGA_PCI_DEVICE_IDPCI_DEVICE_ID_VMWARE_SVGA#endifenum{/* ID 0, 1 and 2 registers */SVGA_REG_ID=0,SVGA_REG_ENABLE=1,SVGA_REG_WIDTH=2,SVGA_REG_HEIGHT=3,SVGA_REG_MAX_WIDTH=4,SVGA_REG_MAX_HEIGHT=5,SVGA_REG_DEPTH=6,SVGA_REG_BITS_PER_PIXEL=7,/* Current bpp in the guest */SVGA_REG_PSEUDOCOLOR=8,SVGA_REG_RED_MASK=9,SVGA_REG_GREEN_MASK=10,SVGA_REG_BLUE_MASK=11,SVGA_REG_BYTES_PER_LINE=12,SVGA_REG_FB_START=13,SVGA_REG_FB_OFFSET=14,SVGA_REG_VRAM_SIZE=15,SVGA_REG_FB_SIZE=16,/* ID 1 and 2 registers */SVGA_REG_CAPABILITIES=17,SVGA_REG_MEM_START=18,/* Memory for command FIFO */SVGA_REG_MEM_SIZE=19,SVGA_REG_CONFIG_DONE=20,/* Set when memory area configured */SVGA_REG_SYNC=21,/* Write to force synchronization */SVGA_REG_BUSY=22,/* Read to check if sync is done */SVGA_REG_GUEST_ID=23,/* Set guest OS identifier */SVGA_REG_CURSOR_ID=24,/* ID of cursor */SVGA_REG_CURSOR_X=25,/* Set cursor X position */SVGA_REG_CURSOR_Y=26,/* Set cursor Y position */SVGA_REG_CURSOR_ON=27,/* Turn cursor on/off */SVGA_REG_HOST_BITS_PER_PIXEL=28,/* Current bpp in the host */SVGA_REG_SCRATCH_SIZE=29,/* Number of scratch registers */SVGA_REG_MEM_REGS=30,/* Number of FIFO registers */SVGA_REG_NUM_DISPLAYS=31,/* Number of guest displays */SVGA_REG_PITCHLOCK=32,/* Fixed pitch for all modes */SVGA_PALETTE_BASE=1024,/* Base of SVGA color map */SVGA_PALETTE_END=SVGA_PALETTE_BASE+767,SVGA_SCRATCH_BASE=SVGA_PALETTE_BASE+768,};#defineSVGA_CAP_NONE0#defineSVGA_CAP_RECT_FILL(1<<0)#defineSVGA_CAP_RECT_COPY(1<<1)#defineSVGA_CAP_RECT_PAT_FILL(1<<2)#defineSVGA_CAP_LEGACY_OFFSCREEN(1<<3)#defineSVGA_CAP_RASTER_OP(1<<4)#defineSVGA_CAP_CURSOR(1<<5)#defineSVGA_CAP_CURSOR_BYPASS(1<<6)#defineSVGA_CAP_CURSOR_BYPASS_2(1<<7)#defineSVGA_CAP_8BIT_EMULATION(1<<8)#defineSVGA_CAP_ALPHA_CURSOR(1<<9)#defineSVGA_CAP_GLYPH(1<<10)#defineSVGA_CAP_GLYPH_CLIPPING(1<<11)#defineSVGA_CAP_OFFSCREEN_1(1<<12)#defineSVGA_CAP_ALPHA_BLEND(1<<13)#defineSVGA_CAP_3D(1<<14)#defineSVGA_CAP_EXTENDED_FIFO(1<<15)#defineSVGA_CAP_MULTIMON(1<<16)#defineSVGA_CAP_PITCHLOCK(1<<17)/**FIFOoffsets(seenasanarrayof32-bitwords)*/enum{/**TheoriginaldefinedFIFOoffsets*/SVGA_FIFO_MIN=0,SVGA_FIFO_MAX,/* The distance from MIN to MAX must be at least 10K */SVGA_FIFO_NEXT_CMD,SVGA_FIFO_STOP,/**AdditionaloffsetsaddedasofSVGA_CAP_EXTENDED_FIFO*/SVGA_FIFO_CAPABILITIES=4,SVGA_FIFO_FLAGS,SVGA_FIFO_FENCE,SVGA_FIFO_3D_HWVERSION,SVGA_FIFO_PITCHLOCK,};#defineSVGA_FIFO_CAP_NONE0#defineSVGA_FIFO_CAP_FENCE(1<<0)#defineSVGA_FIFO_CAP_ACCELFRONT(1<<1)#defineSVGA_FIFO_CAP_PITCHLOCK(1<<2)#defineSVGA_FIFO_FLAG_NONE0#defineSVGA_FIFO_FLAG_ACCELFRONT(1<<0)/* These values can probably be changed arbitrarily. */#defineSVGA_SCRATCH_SIZE0x8000#defineSVGA_MAX_WIDTH2360#defineSVGA_MAX_HEIGHT1770#ifdefVERBOSE#defineGUEST_OS_BASE0x5001staticconstchar*vmsvga_guest_id[]={
};#endifenum{SVGA_CMD_INVALID_CMD=0,SVGA_CMD_UPDATE=1,SVGA_CMD_RECT_FILL=2,SVGA_CMD_RECT_COPY=3,SVGA_CMD_DEFINE_BITMAP=4,SVGA_CMD_DEFINE_BITMAP_SCANLINE=5,SVGA_CMD_DEFINE_PIXMAP=6,SVGA_CMD_DEFINE_PIXMAP_SCANLINE=7,SVGA_CMD_RECT_BITMAP_FILL=8,SVGA_CMD_RECT_PIXMAP_FILL=9,SVGA_CMD_RECT_BITMAP_COPY=10,SVGA_CMD_RECT_PIXMAP_COPY=11,SVGA_CMD_FREE_OBJECT=12,SVGA_CMD_RECT_ROP_FILL=13,SVGA_CMD_RECT_ROP_COPY=14,SVGA_CMD_RECT_ROP_BITMAP_FILL=15,SVGA_CMD_RECT_ROP_PIXMAP_FILL=16,SVGA_CMD_RECT_ROP_BITMAP_COPY=17,SVGA_CMD_RECT_ROP_PIXMAP_COPY=18,SVGA_CMD_DEFINE_CURSOR=19,SVGA_CMD_DISPLAY_CURSOR=20,SVGA_CMD_MOVE_CURSOR=21,SVGA_CMD_DEFINE_ALPHA_CURSOR=22,SVGA_CMD_DRAW_GLYPH=23,SVGA_CMD_DRAW_GLYPH_CLIPPED=24,SVGA_CMD_UPDATE_VERBOSE=25,SVGA_CMD_SURFACE_FILL=26,SVGA_CMD_SURFACE_COPY=27,SVGA_CMD_SURFACE_ALPHA_BLEND=28,SVGA_CMD_FRONT_ROP_FILL=29,SVGA_CMD_FENCE=30,};/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */enum{SVGA_CURSOR_ON_HIDE=0,SVGA_CURSOR_ON_SHOW=1,SVGA_CURSOR_ON_REMOVE_FROM_FB=2,SVGA_CURSOR_ON_RESTORE_TO_FB=3,};staticinlinevoidvmsvga_update_rect(structvmsvga_state_s*s,intx,inty,intw,inth){#ifndefDIRECT_VRAM
intline;intbypl;intwidth;intstart;uint8_t*src;uint8_t*dst;if(x+w>s->width){fprintf(stderr,"%s: update width too large x: %d, w: %d\n",__FUNCTION__,x,w);x=MIN(x,s->width);w=s->width-x;}if(y+h>s->height){fprintf(stderr,"%s: update height too large y: %d, h: %d\n",__FUNCTION__,y,h);y=MIN(y,s->height);h=s->height-y;}line=h;bypl=s->bypp*s->width;width=s->bypp*w;start=s->bypp*x+bypl*y;src=s->vram+start;dst=s->ds->data+start;
caseSVGA_REG_MEM_SIZE:returnSVGA_FIFO_SIZE;caseSVGA_REG_CONFIG_DONE:returns->config;caseSVGA_REG_SYNC:caseSVGA_REG_BUSY:returns->syncing;caseSVGA_REG_GUEST_ID:returns->guest;caseSVGA_REG_CURSOR_ID:returns->cursor.id;caseSVGA_REG_CURSOR_X:returns->cursor.x;caseSVGA_REG_CURSOR_Y:returns->cursor.x;caseSVGA_REG_CURSOR_ON:returns->cursor.on;caseSVGA_REG_HOST_BITS_PER_PIXEL:return(s->depth+7)&~7;caseSVGA_REG_SCRATCH_SIZE:returns->scratch_size;caseSVGA_REG_MEM_REGS:caseSVGA_REG_NUM_DISPLAYS:caseSVGA_REG_PITCHLOCK:caseSVGA_PALETTE_BASE...SVGA_PALETTE_END:return0;default:if(s->index>=SVGA_SCRATCH_BASE&&s->index<SVGA_SCRATCH_BASE+s->scratch_size)returns->scratch[s->index-SVGA_SCRATCH_BASE];printf("%s: Bad register %02x\n",__FUNCTION__,s->index);}return0;}staticvoidvmsvga_value_write(void*opaque,uint32_taddress,uint32_tvalue){structvmsvga_state_s*s=(structvmsvga_state_s*)opaque;switch(s->index){caseSVGA_REG_ID:if(value==SVGA_ID_2||value==SVGA_ID_1||value==SVGA_ID_0)s->svgaid=value;break;caseSVGA_REG_ENABLE:
s->width=-1;s->height=-1;s->invalidated=1;#ifdefEMBED_STDVGAs->invalidate(opaque);#endifif(s->enable)s->fb_size=((s->depth+7)>>3)*s->new_width*s->new_height;break;caseSVGA_REG_WIDTH:s->new_width=value;s->invalidated=1;break;caseSVGA_REG_HEIGHT:s->new_height=value;s->invalidated=1;break;caseSVGA_REG_DEPTH:caseSVGA_REG_BITS_PER_PIXEL:if(value!=s->depth){printf("%s: Bad colour depth: %i bits\n",__FUNCTION__,value);s->config=0;}break;caseSVGA_REG_CONFIG_DONE:if(value){s->fifo=(uint32_t*)&s->vram[s->vram_size-SVGA_FIFO_SIZE];/* Check range and alignment. */if((s->cmd->min|s->cmd->max|s->cmd->next_cmd|s->cmd->stop)&3)break;if(s->cmd->min<(uint8_t*)s->cmd->fifo-(uint8_t*)s->fifo)break;if(s->cmd->max>SVGA_FIFO_SIZE)break;if(s->cmd->max<s->cmd->min+10*1024)break;}
break;caseSVGA_REG_SYNC:s->syncing=1;vmsvga_fifo_run(s);/* Or should we just wait for update_display? */break;caseSVGA_REG_GUEST_ID:s->guest=value;#ifdefVERBOSEif(value>=GUEST_OS_BASE&&value<GUEST_OS_BASE+sizeof(vmsvga_guest_id)/sizeof(*vmsvga_guest_id))printf("%s: guest runs %s.\n",__FUNCTION__,vmsvga_guest_id[value-GUEST_OS_BASE]);#endifbreak;caseSVGA_REG_CURSOR_ID:s->cursor.id=value;break;caseSVGA_REG_CURSOR_X:s->cursor.x=value;break;caseSVGA_REG_CURSOR_Y:s->cursor.y=value;break;caseSVGA_REG_CURSOR_ON:s->cursor.on|=(value==SVGA_CURSOR_ON_SHOW);s->cursor.on&=(value!=SVGA_CURSOR_ON_HIDE);#ifdefHW_MOUSE_ACCELif(s->ds->mouse_set&&value<=SVGA_CURSOR_ON_SHOW)s->ds->mouse_set(s->cursor.x,s->cursor.y,s->cursor.on);#endifbreak;caseSVGA_REG_MEM_REGS:caseSVGA_REG_NUM_DISPLAYS:caseSVGA_REG_PITCHLOCK:caseSVGA_PALETTE_BASE...SVGA_PALETTE_END:break;default:if(s->index>=SVGA_SCRATCH_BASE&&s->index<SVGA_SCRATCH_BASE+s->scratch_size){s->scratch[s->index-SVGA_SCRATCH_BASE]=value;break;}printf("%s: Bad register %02x\n",__FUNCTION__,s->index);}}staticuint32_tvmsvga_bios_read(void*opaque,uint32_taddress){printf("%s: what are we supposed to return?\n",__FUNCTION__);return0xcafe;}staticvoidvmsvga_bios_write(void*opaque,uint32_taddress,uint32_tdata){printf("%s: what are we supposed to do with (%08x)?\n",__FUNCTION__,data);}staticinlinevoidvmsvga_size(structvmsvga_state_s*s){if(s->new_width!=s->width||s->new_height!=s->height){s->width=s->new_width;s->height=s->new_height;dpy_resize(s->ds,s->width,s->height);s->invalidated=1;}}staticvoidvmsvga_update_display(void*opaque){structvmsvga_state_s*s=(structvmsvga_state_s*)opaque;if(!s->enable){#ifdefEMBED_STDVGAs->update(opaque);#endifreturn;}vmsvga_size(s);vmsvga_fifo_run(s);vmsvga_update_rect_flush(s);/**IsitmoreefficienttolookatvramVGA-dirtybitsorwait*forthedrivertoissueSVGA_CMD_UPDATE?*/if(s->invalidated){s->invalidated=0;vmsvga_update_screen(s);}}staticvoidvmsvga_reset(structvmsvga_state_s*s){s->index=0;s->enable=0;s->config=0;s->width=-1;s->height=-1;s->svgaid=SVGA_ID;s->depth=s->ds->depth?s->ds->depth:24;s->bypp=(s->depth+7)>>3;s->cursor.on=0;s->redraw_fifo_first=0;s->redraw_fifo_last=0;switch(s->depth){case8:s->wred=0x00000007;s->wgreen=0x00000038;s->wblue=0x000000c0;break;case15:s->wred=0x0000001f;s->wgreen=0x000003e0;s->wblue=0x00007c00;break;case16:s->wred=0x0000001f;s->wgreen=0x000007e0;s->wblue=0x0000f800;break;case24:
if(s->enable&&depth!=s->depth){printf("%s: need colour depth of %i bits to resume operation.\n",__FUNCTION__,depth);return-EINVAL;}s->invalidated=1;if(s->config)s->fifo=(uint32_t*)&s->vram[s->vram_size-SVGA_FIFO_SIZE];return0;}staticvoidvmsvga_init(structvmsvga_state_s*s,DisplayState*ds,uint8_t*vga_ram_base,unsignedlongvga_ram_offset,intvga_ram_size){s->ds=ds;s->vram=vga_ram_base;s->vram_size=vga_ram_size;