VMWare SVGA-II

From OSDev Wiki
Jump to navigation Jump to search

The VMware SVGA-II device is a graphics card simulated by VMware and QEMU. It is a PCI SVGA-compatible graphics card that implements 2D and 3D acceleration as well as hardware cursor support.

Hardware Detection

The procedure of detecting its presence is by detecting if there is a PCI device with the vendor ID 0x15AD and the device ID 0x0405 on the bus.

I/O Ports

The base I/O port (SVGA_PORT_BASE) is not fixed. The driver has to substract 1 from the BAR0 in the PCI configuration to get it. The following port offsets are exposed by the device:

  • SVGA_INDEX (offset 0)
  • SVGA_VALUE (offset 1)
  • SVGA_BIOS (offset 2)
  • SVGA_IRQSTATUS (offset 8)

Internal Registers

Although there are more registers (all shown in the Official Developer Kit linked below), the most important ones are:

  • SVGA_REG_ID (0) - register used to negociate specification ID
  • SVGA_REG_ENABLE (1) - flag set by the driver when the device should enter SVGA mode
  • SVGA_REG_WIDTH (2) - current screen width
  • SVGA_REG_HEIGHT (3) - current screen height
  • SVGA_REG_MAX_WIDTH (4) - maximum supported screen width
  • SVGA_REG_MAX_HEIGHT (5) - maximum supported screen height
  • SVGA_REG_BPP (7) - current screen bits per pixel
  • SVGA_REG_FB_START (13) - address in system memory of the frame buffer
  • SVGA_REG_FB_OFFSET (14) - offset in the frame buffer to the visible pixel data
  • SVGA_REG_VRAM_SIZE (15) - size of the video RAM
  • SVGA_REG_FB_SIZE (16) - size of the frame buffer
  • SVGA_REG_CAPABILITIES (17) - device capabilities
  • SVGA_REG_FIFO_START (18) - address in system memory of the FIFO
  • SVGA_REG_FIFO_SIZE (19) - FIFO size
  • SVGA_REG_CONFIG_DONE (20) - flag to enable FIFO operation
  • SVGA_REG_SYNC (21) - flag set by the driver to flush FIFO changes
  • SVGA_REG_BUSY (22) - flag set by the FIFO when it's processed

Reading or writing to an internal register is very easy. The driver has to write a long to the port SVGA_PORT_BASE + SVGA_INDEX corresponding to the register index then write the data or read it from the port SVGA_PORT_BASE + SVGA_VALUE.

Initialising the Device

The procedure of initialisation is:

  • Detect the device on the PCI bus (vendor 0x15AD, device 0x0405)
  • Enable memory, I/O and bus mastering by ORing the command field (in the PCI configuration) with 0x7;
  • Calculate the I/O base port from substracting 1 from the PCI BAR0.
  • Set the SVGA_REG_ID register to 0x90000002 (indicate latest specification ID)
  • Check if it is supported by reading back the register and comparing the result
  • Read the frame buffer and FIFO addresses from the registers SVGA_REG_FB_START and SVGA_REG_FIFO_START
  • Read the frame buffer offset and the capabilities field from the registers SVGA_REG_FB_OFFSET and SVGA_REG_CAPABILITIES
  • Read the FIFO size from the register SVGA_REG_FIFO_SIZE
  • Identity map the FIFO memory
  • Initialise the FIFO (explained in next chapter)
  • Write 1 to SVGA_REG_ENABLE

Capabilities

Using the FIFO

The FIFO is an array of 32-bit elements which is filled by the driver with commands that the device has to execute.

TODO: write something about every command The supported FIFO commands are:

  • SVGA_CMD_UPDATE (1) -> Update the screen; Operands: startX, startY, width, height
  • SVGA_CMD_RECT_COPY (3) -> Copy a rectangle from one area of the visible frame buffer to another; Operands: srcX, srcY, destX, destY, width, height (Requires SVGA_CAP_RECT_COPY)
  • SVGA_CMD_DEFINE_CURSOR (19)
  • SVGA_CMD_DEFINE_ALPHA_CURSOR (22)
  • SVGA_CMD_UPDATE_VERBOSE (25) -> Just like SVGA_CMD_UPDATE but adds another operand named reason
  • SVGA_CMD_FRONT_ROP_FILL (29)
  • SVGA_CMD_FENCE (30)
  • SVGA_CMD_ESCAPE (33)
  • SVGA_CMD_DEFINE_SCREEN (34)
  • SVGA_CMD_DESTROY_SCREEN (35)
  • SVGA_CMD_DEFINE_GMRFB (36)
  • SVGA_CMD_BLIT_GMRFB_TO_SCREEN (37)
  • SVGA_CMD_BLIT_SCREEN_TO_GMRFB (38)
  • SVGA_CMD_ANNOTATION_FILL (39)
  • SVGA_CMD_ANNOTATION_COPY (40)
  • SVGA_CMD_DEFINE_GMR2 (41)
  • SVGA_CMD_REMAP_GMR2 (42)

To write a command, the driver has to first sequentially write its ID and then the operands to the FIFO.

The FIFO has many registers that the driver can mess with (293). The most important ones are:

  • SVGA_FIFO_MIN (0) - start of command queue
  • SVGA_FIFO_MAX (1) - end of command queue
  • SVGA_FIFO_NEXT_CMD (2) - next command (offset in bytes)
  • SVGA_FIFO_STOP (3) - todo: explain what SVGA_FIFO_STOP does

Writing/reading to/from those is as easy as to write/read data to/from the FIFO address + register index.

To initialise the FIFO, the driver has to:

  • Set SVGA_FIFO_MIN, SVGA_FIFO_NEXT_CMD and SVGA_FIFO_STOP registers to 293 * 4 (point right after the 293 32-bit registers)
  • Set SVGA_FIFO_MAX to the FIFO size
  • Set SVGA_REG_CONFIG_DONE to 1

To sequentially write data to the FIFO the driver has to:

  • Write the data to the FIFO address + value of SVGA_FIFO_NEXT_CMD (Warning! SVGA_FIFO_NEXT_CMD provides the offset in bytes)
  • Increment SVGA_FIFO_NEXT_CMD by 4

Setting a new Mode

To set a new mode the driver has to:

  • Write the new width, height and bits per pixel values to the coresponding registers (SVGA_REG_WIDTH,SVGA_REG_HEIGHT,SVGA_REG_BPP)
  • Read again the frame buffer offset from SVGA_REG_FB_OFFSET
  • Set SVGA_REG_ENABLE to 1

2D Acceleration

3D Acceleration

Official Developer Kit

VMware SVGA Device Developer Kit