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