Home | History | Annotate | Download | only in QemuVideoDxe
      1 /** @file
      2   Graphics Output Protocol functions for the QEMU video controller.
      3 
      4   Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution. The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Qemu.h"
     17 
     18 
     19 ///
     20 /// Generic Attribute Controller Register Settings
     21 ///
     22 UINT8  AttributeController[21] = {
     23   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     24   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
     25   0x41, 0x00, 0x0F, 0x00, 0x00
     26 };
     27 
     28 ///
     29 /// Generic Graphics Controller Register Settings
     30 ///
     31 UINT8 GraphicsController[9] = {
     32   0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF
     33 };
     34 
     35 //
     36 // 640 x 480 x 256 color @ 60 Hertz
     37 //
     38 UINT8 Crtc_640_480_256_60[28] = {
     39   0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
     40   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     41   0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3,
     42   0xff, 0x00, 0x00, 0x22
     43 };
     44 
     45 UINT8 Crtc_640_480_32bpp_60[28] = {
     46   0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e,
     47   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     48   0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3,
     49   0xff, 0x00, 0x00, 0x32
     50 };
     51 
     52 UINT16 Seq_640_480_256_60[15] = {
     53   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
     54   0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
     55 };
     56 
     57 UINT16 Seq_640_480_32bpp_60[15] = {
     58   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
     59   0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e
     60 };
     61 
     62 //
     63 // 800 x 600 x 256 color @ 60 Hertz
     64 //
     65 UINT8 Crtc_800_600_256_60[28] = {
     66   0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
     67   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     68   0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3,
     69   0xFF, 0x00, 0x00, 0x22
     70 };
     71 
     72 UINT8 Crtc_800_600_32bpp_60[28] = {
     73   0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0,
     74   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     75   0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3,
     76   0xFF, 0x00, 0x00, 0x32
     77 };
     78 
     79 UINT16 Seq_800_600_256_60[15] = {
     80   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
     81   0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
     82 };
     83 
     84 UINT16 Seq_800_600_32bpp_60[15] = {
     85   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
     86   0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e
     87 };
     88 
     89 UINT8 Crtc_960_720_32bpp_60[28] = {
     90   0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
     91   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     92   0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
     93   0xFF, 0x4A, 0x00, 0x32
     94 };
     95 
     96 UINT16 Seq_960_720_32bpp_60[15] = {
     97   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
     98   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
     99 };
    100 
    101 //
    102 // 1024 x 768 x 256 color @ 60 Hertz
    103 //
    104 UINT8 Crtc_1024_768_256_60[28] = {
    105   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
    106   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    107   0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
    108   0xFF, 0x4A, 0x00, 0x22
    109 };
    110 
    111 UINT16 Seq_1024_768_256_60[15] = {
    112   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b,
    113   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
    114 };
    115 
    116 //
    117 // 1024 x 768 x 24-bit color @ 60 Hertz
    118 //
    119 UINT8 Crtc_1024_768_24bpp_60[28] = {
    120   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
    121   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    122   0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3,
    123   0xFF, 0x4A, 0x00, 0x32
    124 };
    125 
    126 UINT16 Seq_1024_768_24bpp_60[15] = {
    127   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b,
    128   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
    129 };
    130 
    131 UINT8 Crtc_1024_768_32bpp_60[28] = {
    132   0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD,
    133   0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    134   0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3,
    135   0xFF, 0x4A, 0x00, 0x32
    136 };
    137 
    138 UINT16 Seq_1024_768_32bpp_60[15] = {
    139   0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b,
    140   0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e
    141 };
    142 
    143 ///
    144 /// Table of supported video modes
    145 ///
    146 QEMU_VIDEO_CIRRUS_MODES  QemuVideoCirrusModes[] = {
    147 //  {  640, 480, 8, Crtc_640_480_256_60,  Seq_640_480_256_60,  0xe3 },
    148 //  {  800, 600, 8, Crtc_800_600_256_60,  Seq_800_600_256_60,  0xef },
    149   {  640, 480, 32, Crtc_640_480_32bpp_60,  Seq_640_480_32bpp_60,  0xef },
    150   {  800, 600, 32, Crtc_800_600_32bpp_60,  Seq_800_600_32bpp_60,  0xef },
    151 //  { 1024, 768, 8, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef }
    152   { 1024, 768, 24, Crtc_1024_768_24bpp_60, Seq_1024_768_24bpp_60, 0xef }
    153 //  { 1024, 768, 32, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
    154 //  { 960, 720, 32, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef }
    155 };
    156 
    157 #define QEMU_VIDEO_CIRRUS_MODE_COUNT \
    158   (ARRAY_SIZE (QemuVideoCirrusModes))
    159 
    160 /**
    161   Construct the valid video modes for QemuVideo.
    162 
    163 **/
    164 EFI_STATUS
    165 QemuVideoCirrusModeSetup (
    166   QEMU_VIDEO_PRIVATE_DATA  *Private
    167   )
    168 {
    169   UINT32                                 Index;
    170   QEMU_VIDEO_MODE_DATA                   *ModeData;
    171   QEMU_VIDEO_CIRRUS_MODES                *VideoMode;
    172 
    173   //
    174   // Setup Video Modes
    175   //
    176   Private->ModeData = AllocatePool (
    177                         sizeof (Private->ModeData[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT
    178                         );
    179   if (Private->ModeData == NULL) {
    180     return EFI_OUT_OF_RESOURCES;
    181   }
    182   ModeData = Private->ModeData;
    183   VideoMode = &QemuVideoCirrusModes[0];
    184   for (Index = 0; Index < QEMU_VIDEO_CIRRUS_MODE_COUNT; Index ++) {
    185     ModeData->InternalModeIndex = Index;
    186     ModeData->HorizontalResolution          = VideoMode->Width;
    187     ModeData->VerticalResolution            = VideoMode->Height;
    188     ModeData->ColorDepth                    = VideoMode->ColorDepth;
    189     DEBUG ((EFI_D_INFO,
    190       "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit\n",
    191       (INT32) (ModeData - Private->ModeData),
    192       ModeData->InternalModeIndex,
    193       ModeData->HorizontalResolution,
    194       ModeData->VerticalResolution,
    195       ModeData->ColorDepth
    196       ));
    197 
    198     ModeData ++ ;
    199     VideoMode ++;
    200   }
    201   Private->MaxMode = ModeData - Private->ModeData;
    202 
    203   return EFI_SUCCESS;
    204 }
    205 
    206 ///
    207 /// Table of supported video modes
    208 ///
    209 QEMU_VIDEO_BOCHS_MODES  QemuVideoBochsModes[] = {
    210   {  640,  480, 32 },
    211   {  800,  480, 32 },
    212   {  800,  600, 32 },
    213   {  832,  624, 32 },
    214   {  960,  640, 32 },
    215   { 1024,  600, 32 },
    216   { 1024,  768, 32 },
    217   { 1152,  864, 32 },
    218   { 1152,  870, 32 },
    219   { 1280,  720, 32 },
    220   { 1280,  760, 32 },
    221   { 1280,  768, 32 },
    222   { 1280,  800, 32 },
    223   { 1280,  960, 32 },
    224   { 1280, 1024, 32 },
    225   { 1360,  768, 32 },
    226   { 1366,  768, 32 },
    227   { 1400, 1050, 32 },
    228   { 1440,  900, 32 },
    229   { 1600,  900, 32 },
    230   { 1600, 1200, 32 },
    231   { 1680, 1050, 32 },
    232   { 1920, 1080, 32 },
    233   { 1920, 1200, 32 },
    234   { 1920, 1440, 32 },
    235   { 2000, 2000, 32 },
    236   { 2048, 1536, 32 },
    237   { 2048, 2048, 32 },
    238   { 2560, 1440, 32 },
    239   { 2560, 1600, 32 },
    240   { 2560, 2048, 32 },
    241   { 2800, 2100, 32 },
    242   { 3200, 2400, 32 },
    243   { 3840, 2160, 32 },
    244   { 4096, 2160, 32 },
    245   { 7680, 4320, 32 },
    246   { 8192, 4320, 32 }
    247 };
    248 
    249 #define QEMU_VIDEO_BOCHS_MODE_COUNT \
    250   (ARRAY_SIZE (QemuVideoBochsModes))
    251 
    252 EFI_STATUS
    253 QemuVideoBochsModeSetup (
    254   QEMU_VIDEO_PRIVATE_DATA  *Private,
    255   BOOLEAN                  IsQxl
    256   )
    257 {
    258   UINT32                                 AvailableFbSize;
    259   UINT32                                 Index;
    260   QEMU_VIDEO_MODE_DATA                   *ModeData;
    261   QEMU_VIDEO_BOCHS_MODES                 *VideoMode;
    262 
    263   //
    264   // Fetch the available framebuffer size.
    265   //
    266   // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the
    267   // drawable framebuffer. Up to and including qemu-2.1 however it used to
    268   // return the size of PCI BAR 0 (ie. the full video RAM size).
    269   //
    270   // On stdvga the two concepts coincide with each other; the full memory size
    271   // is usable for drawing.
    272   //
    273   // On QXL however, only a leading segment, "surface 0", can be used for
    274   // drawing; the rest of the video memory is used for the QXL guest-host
    275   // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of
    276   // "surface 0", but since it doesn't (up to and including qemu-2.1), we
    277   // retrieve the size of the drawable portion from a field in the QXL ROM BAR,
    278   // where it is also available.
    279   //
    280   if (IsQxl) {
    281     UINT32 Signature;
    282     UINT32 DrawStart;
    283 
    284     Signature = 0;
    285     DrawStart = 0xFFFFFFFF;
    286     AvailableFbSize = 0;
    287     if (EFI_ERROR (
    288           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
    289                                 PCI_BAR_IDX2, 0, 1, &Signature)) ||
    290         Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O') ||
    291         EFI_ERROR (
    292           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
    293                                 PCI_BAR_IDX2, 36, 1, &DrawStart)) ||
    294         DrawStart != 0 ||
    295         EFI_ERROR (
    296           Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32,
    297                                 PCI_BAR_IDX2, 40, 1, &AvailableFbSize))) {
    298       DEBUG ((EFI_D_ERROR, "%a: can't read size of drawable buffer from QXL "
    299         "ROM\n", __FUNCTION__));
    300       return EFI_NOT_FOUND;
    301     }
    302   } else {
    303     AvailableFbSize  = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
    304     AvailableFbSize *= SIZE_64KB;
    305   }
    306   DEBUG ((EFI_D_INFO, "%a: AvailableFbSize=0x%x\n", __FUNCTION__,
    307     AvailableFbSize));
    308 
    309   //
    310   // Setup Video Modes
    311   //
    312   Private->ModeData = AllocatePool (
    313                         sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT
    314                         );
    315   if (Private->ModeData == NULL) {
    316     return EFI_OUT_OF_RESOURCES;
    317   }
    318   ModeData = Private->ModeData;
    319   VideoMode = &QemuVideoBochsModes[0];
    320   for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index ++) {
    321     UINTN RequiredFbSize;
    322 
    323     ASSERT (VideoMode->ColorDepth % 8 == 0);
    324     RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height *
    325                      (VideoMode->ColorDepth / 8);
    326     if (RequiredFbSize <= AvailableFbSize) {
    327       ModeData->InternalModeIndex    = Index;
    328       ModeData->HorizontalResolution = VideoMode->Width;
    329       ModeData->VerticalResolution   = VideoMode->Height;
    330       ModeData->ColorDepth           = VideoMode->ColorDepth;
    331       DEBUG ((EFI_D_INFO,
    332         "Adding Mode %d as Bochs Internal Mode %d: %dx%d, %d-bit\n",
    333         (INT32) (ModeData - Private->ModeData),
    334         ModeData->InternalModeIndex,
    335         ModeData->HorizontalResolution,
    336         ModeData->VerticalResolution,
    337         ModeData->ColorDepth
    338         ));
    339 
    340       ModeData ++ ;
    341     }
    342     VideoMode ++;
    343   }
    344   Private->MaxMode = ModeData - Private->ModeData;
    345 
    346   return EFI_SUCCESS;
    347 }
    348 
    349