]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
f1c8b295088843421de490dc0a3dc7db4d599b7d
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / VideoDxe / BiosVideo.c
1 /** @file
2 ConsoleOut Routines that speak VGA.
3
4 Copyright (c) 2007 - 2014, 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
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "BiosVideo.h"
18
19 //
20 // EFI Driver Binding Protocol Instance
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
23 BiosVideoDriverBindingSupported,
24 BiosVideoDriverBindingStart,
25 BiosVideoDriverBindingStop,
26 0x3,
27 NULL,
28 NULL
29 };
30
31 //
32 // Global lookup tables for VGA graphics modes
33 //
34 UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
35
36 UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
37
38 UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
39
40 //
41 // Save controller attributes during first start
42 //
43 UINT64 mOriginalPciAttributes;
44 BOOLEAN mPciAttributesSaved = FALSE;
45
46 EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = {
47 { 0x00, 0x00, 0x00, 0x00 },
48 { 0x98, 0x00, 0x00, 0x00 },
49 { 0x00, 0x98, 0x00, 0x00 },
50 { 0x98, 0x98, 0x00, 0x00 },
51 { 0x00, 0x00, 0x98, 0x00 },
52 { 0x98, 0x00, 0x98, 0x00 },
53 { 0x00, 0x98, 0x98, 0x00 },
54 { 0x98, 0x98, 0x98, 0x00 },
55 { 0x10, 0x10, 0x10, 0x00 },
56 { 0xff, 0x10, 0x10, 0x00 },
57 { 0x10, 0xff, 0x10, 0x00 },
58 { 0xff, 0xff, 0x10, 0x00 },
59 { 0x10, 0x10, 0xff, 0x00 },
60 { 0xf0, 0x10, 0xff, 0x00 },
61 { 0x10, 0xff, 0xff, 0x00 },
62 { 0xff, 0xff, 0xff, 0x00 }
63 };
64
65 //
66 // Standard timing defined by VESA EDID
67 //
68 VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {
69 //
70 // Established Timing I
71 //
72 {800, 600, 60},
73 {800, 600, 56},
74 {640, 480, 75},
75 {640, 480, 72},
76 {640, 480, 67},
77 {640, 480, 60},
78 {720, 400, 88},
79 {720, 400, 70},
80 //
81 // Established Timing II
82 //
83 {1280, 1024, 75},
84 {1024, 768, 75},
85 {1024, 768, 70},
86 {1024, 768, 60},
87 {1024, 768, 87},
88 {832, 624, 75},
89 {800, 600, 75},
90 {800, 600, 72},
91 //
92 // Established Timing III
93 //
94 {1152, 870, 75}
95 };
96
97 /**
98 Supported.
99
100 @param This Pointer to driver binding protocol
101 @param Controller Controller handle to connect
102 @param RemainingDevicePath A pointer to the remaining portion of a device
103 path
104
105 @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
106 driver, Otherwise, this controller cannot be
107 managed by this driver
108
109 **/
110 EFI_STATUS
111 EFIAPI
112 BiosVideoDriverBindingSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL *This,
114 IN EFI_HANDLE Controller,
115 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
116 )
117 {
118 EFI_STATUS Status;
119 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
120 EFI_PCI_IO_PROTOCOL *PciIo;
121 PCI_TYPE00 Pci;
122 EFI_DEV_PATH *Node;
123
124 //
125 // See if the Legacy BIOS Protocol is available
126 //
127 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
128 if (EFI_ERROR (Status)) {
129 return Status;
130 }
131
132 //
133 // Open the IO Abstraction(s) needed to perform the supported test
134 //
135 Status = gBS->OpenProtocol (
136 Controller,
137 &gEfiPciIoProtocolGuid,
138 (VOID **) &PciIo,
139 This->DriverBindingHandle,
140 Controller,
141 EFI_OPEN_PROTOCOL_BY_DRIVER
142 );
143 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
144 return Status;
145 }
146
147 if (Status == EFI_ALREADY_STARTED) {
148 //
149 // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,
150 // because VgaMiniPort protocol is installed on controller handle directly.
151 //
152 Status = gBS->OpenProtocol (
153 Controller,
154 &gEfiVgaMiniPortProtocolGuid,
155 NULL,
156 NULL,
157 NULL,
158 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
159 );
160 if (!EFI_ERROR (Status)) {
161 return EFI_ALREADY_STARTED;
162 }
163 }
164 //
165 // See if this is a PCI Graphics Controller by looking at the Command register and
166 // Class Code Register
167 //
168 Status = PciIo->Pci.Read (
169 PciIo,
170 EfiPciIoWidthUint32,
171 0,
172 sizeof (Pci) / sizeof (UINT32),
173 &Pci
174 );
175 if (EFI_ERROR (Status)) {
176 Status = EFI_UNSUPPORTED;
177 goto Done;
178 }
179
180 Status = EFI_UNSUPPORTED;
181 if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
182
183 Status = EFI_SUCCESS;
184 //
185 // If this is a graphics controller,
186 // go further check RemainingDevicePath validation
187 //
188 if (RemainingDevicePath != NULL) {
189 Node = (EFI_DEV_PATH *) RemainingDevicePath;
190 //
191 // Check if RemainingDevicePath is the End of Device Path Node,
192 // if yes, return EFI_SUCCESS
193 //
194 if (!IsDevicePathEnd (Node)) {
195 //
196 // If RemainingDevicePath isn't the End of Device Path Node,
197 // check its validation
198 //
199 if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
200 Node->DevPath.SubType != ACPI_ADR_DP ||
201 DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
202 Status = EFI_UNSUPPORTED;
203 }
204 }
205 }
206 }
207
208 Done:
209 gBS->CloseProtocol (
210 Controller,
211 &gEfiPciIoProtocolGuid,
212 This->DriverBindingHandle,
213 Controller
214 );
215
216 return Status;
217 }
218
219
220 /**
221 Install Graphics Output Protocol onto VGA device handles.
222
223 @param This Pointer to driver binding protocol
224 @param Controller Controller handle to connect
225 @param RemainingDevicePath A pointer to the remaining portion of a device
226 path
227
228 @return EFI_STATUS
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 BiosVideoDriverBindingStart (
234 IN EFI_DRIVER_BINDING_PROTOCOL *This,
235 IN EFI_HANDLE Controller,
236 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
237 )
238 {
239 EFI_STATUS Status;
240 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
241 EFI_PCI_IO_PROTOCOL *PciIo;
242 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
243 UINTN Flags;
244 UINT64 Supports;
245
246 //
247 // Initialize local variables
248 //
249 PciIo = NULL;
250 ParentDevicePath = NULL;
251
252 //
253 //
254 // See if the Legacy BIOS Protocol is available
255 //
256 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
257 if (EFI_ERROR (Status)) {
258 return Status;
259 }
260
261 //
262 // Prepare for status code
263 //
264 Status = gBS->HandleProtocol (
265 Controller,
266 &gEfiDevicePathProtocolGuid,
267 (VOID **) &ParentDevicePath
268 );
269 if (EFI_ERROR (Status)) {
270 return Status;
271 }
272
273 //
274 // Open the IO Abstraction(s) needed
275 //
276 Status = gBS->OpenProtocol (
277 Controller,
278 &gEfiPciIoProtocolGuid,
279 (VOID **) &PciIo,
280 This->DriverBindingHandle,
281 Controller,
282 EFI_OPEN_PROTOCOL_BY_DRIVER
283 );
284 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
285 return Status;
286 }
287
288 //
289 // Save original PCI attributes
290 //
291 if (!mPciAttributesSaved) {
292 Status = PciIo->Attributes (
293 PciIo,
294 EfiPciIoAttributeOperationGet,
295 0,
296 &mOriginalPciAttributes
297 );
298
299 if (EFI_ERROR (Status)) {
300 goto Done;
301 }
302 mPciAttributesSaved = TRUE;
303 }
304
305 //
306 // Get supported PCI attributes
307 //
308 Status = PciIo->Attributes (
309 PciIo,
310 EfiPciIoAttributeOperationSupported,
311 0,
312 &Supports
313 );
314 if (EFI_ERROR (Status)) {
315 goto Done;
316 }
317
318 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
319 if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
320 Status = EFI_UNSUPPORTED;
321 goto Done;
322 }
323
324 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
325 EFI_PROGRESS_CODE,
326 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
327 ParentDevicePath
328 );
329 //
330 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
331 //
332 Status = PciIo->Attributes (
333 PciIo,
334 EfiPciIoAttributeOperationEnable,
335 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,
336 NULL
337 );
338 if (EFI_ERROR (Status)) {
339 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
340 EFI_ERROR_CODE | EFI_ERROR_MINOR,
341 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
342 ParentDevicePath
343 );
344 goto Done;
345 }
346 //
347 // Check to see if there is a legacy option ROM image associated with this PCI device
348 //
349 Status = LegacyBios->CheckPciRom (
350 LegacyBios,
351 Controller,
352 NULL,
353 NULL,
354 &Flags
355 );
356 if (EFI_ERROR (Status)) {
357 goto Done;
358 }
359 //
360 // Post the legacy option ROM if it is available.
361 //
362 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
363 EFI_PROGRESS_CODE,
364 EFI_P_PC_RESET,
365 ParentDevicePath
366 );
367 Status = LegacyBios->InstallPciRom (
368 LegacyBios,
369 Controller,
370 NULL,
371 &Flags,
372 NULL,
373 NULL,
374 NULL,
375 NULL
376 );
377 if (EFI_ERROR (Status)) {
378 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
379 EFI_ERROR_CODE | EFI_ERROR_MINOR,
380 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
381 ParentDevicePath
382 );
383 goto Done;
384 }
385
386 if (RemainingDevicePath != NULL) {
387 if (IsDevicePathEnd (RemainingDevicePath) &&
388 (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {
389 //
390 // If RemainingDevicePath is the End of Device Path Node,
391 // don't create any child device and return EFI_SUCESS
392 Status = EFI_SUCCESS;
393 goto Done;
394 }
395 }
396
397 //
398 // Create child handle and install GraphicsOutputProtocol on it
399 //
400 Status = BiosVideoChildHandleInstall (
401 This,
402 Controller,
403 PciIo,
404 LegacyBios,
405 ParentDevicePath,
406 RemainingDevicePath
407 );
408
409 Done:
410 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
411 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
412 EFI_PROGRESS_CODE,
413 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
414 ParentDevicePath
415 );
416
417 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
418 EFI_PROGRESS_CODE,
419 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
420 ParentDevicePath
421 );
422 if (!HasChildHandle (Controller)) {
423 if (mPciAttributesSaved) {
424 //
425 // Restore original PCI attributes
426 //
427 PciIo->Attributes (
428 PciIo,
429 EfiPciIoAttributeOperationSet,
430 mOriginalPciAttributes,
431 NULL
432 );
433 }
434 }
435 //
436 // Release PCI I/O Protocols on the controller handle.
437 //
438 gBS->CloseProtocol (
439 Controller,
440 &gEfiPciIoProtocolGuid,
441 This->DriverBindingHandle,
442 Controller
443 );
444 }
445
446 return Status;
447 }
448
449
450 /**
451 Stop.
452
453 @param This Pointer to driver binding protocol
454 @param Controller Controller handle to connect
455 @param NumberOfChildren Number of children handle created by this driver
456 @param ChildHandleBuffer Buffer containing child handle created
457
458 @retval EFI_SUCCESS Driver disconnected successfully from controller
459 @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
460
461 **/
462 EFI_STATUS
463 EFIAPI
464 BiosVideoDriverBindingStop (
465 IN EFI_DRIVER_BINDING_PROTOCOL *This,
466 IN EFI_HANDLE Controller,
467 IN UINTN NumberOfChildren,
468 IN EFI_HANDLE *ChildHandleBuffer
469 )
470 {
471 EFI_STATUS Status;
472 BOOLEAN AllChildrenStopped;
473 UINTN Index;
474 EFI_PCI_IO_PROTOCOL *PciIo;
475
476 AllChildrenStopped = TRUE;
477
478 if (NumberOfChildren == 0) {
479 //
480 // Close PCI I/O protocol on the controller handle
481 //
482 gBS->CloseProtocol (
483 Controller,
484 &gEfiPciIoProtocolGuid,
485 This->DriverBindingHandle,
486 Controller
487 );
488
489 return EFI_SUCCESS;
490 }
491
492 for (Index = 0; Index < NumberOfChildren; Index++) {
493 Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
494
495 if (EFI_ERROR (Status)) {
496 AllChildrenStopped = FALSE;
497 }
498 }
499
500 if (!AllChildrenStopped) {
501 return EFI_DEVICE_ERROR;
502 }
503
504 if (!HasChildHandle (Controller)) {
505 if (mPciAttributesSaved) {
506 Status = gBS->HandleProtocol (
507 Controller,
508 &gEfiPciIoProtocolGuid,
509 (VOID **) &PciIo
510 );
511 ASSERT_EFI_ERROR (Status);
512
513 //
514 // Restore original PCI attributes
515 //
516 Status = PciIo->Attributes (
517 PciIo,
518 EfiPciIoAttributeOperationSet,
519 mOriginalPciAttributes,
520 NULL
521 );
522 ASSERT_EFI_ERROR (Status);
523 }
524 }
525
526
527 return EFI_SUCCESS;
528 }
529
530
531 /**
532 Install child handles if the Handle supports MBR format.
533
534 @param This Calling context.
535 @param ParentHandle Parent Handle
536 @param ParentPciIo Parent PciIo interface
537 @param ParentLegacyBios Parent LegacyBios interface
538 @param ParentDevicePath Parent Device Path
539 @param RemainingDevicePath Remaining Device Path
540
541 @retval EFI_SUCCESS If a child handle was added
542 @retval other A child handle was not added
543
544 **/
545 EFI_STATUS
546 BiosVideoChildHandleInstall (
547 IN EFI_DRIVER_BINDING_PROTOCOL *This,
548 IN EFI_HANDLE ParentHandle,
549 IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
550 IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,
551 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
552 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
553 )
554 {
555 EFI_STATUS Status;
556 BIOS_VIDEO_DEV *BiosVideoPrivate;
557 PCI_TYPE00 Pci;
558 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
559 BOOLEAN ProtocolInstalled;
560
561 //
562 // Allocate the private device structure for video device
563 //
564 BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (
565 sizeof (BIOS_VIDEO_DEV)
566 );
567 if (NULL == BiosVideoPrivate) {
568 Status = EFI_OUT_OF_RESOURCES;
569 goto Done;
570 }
571
572 //
573 // See if this is a VGA compatible controller or not
574 //
575 Status = ParentPciIo->Pci.Read (
576 ParentPciIo,
577 EfiPciIoWidthUint32,
578 0,
579 sizeof (Pci) / sizeof (UINT32),
580 &Pci
581 );
582 if (EFI_ERROR (Status)) {
583 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
584 EFI_ERROR_CODE | EFI_ERROR_MINOR,
585 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
586 ParentDevicePath
587 );
588 goto Done;
589 }
590 BiosVideoPrivate->VgaCompatible = FALSE;
591 if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {
592 BiosVideoPrivate->VgaCompatible = TRUE;
593 }
594
595 if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {
596 BiosVideoPrivate->VgaCompatible = TRUE;
597 }
598
599 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
600 //
601 // Create EXIT_BOOT_SERIVES Event
602 //
603 Status = gBS->CreateEventEx (
604 EVT_NOTIFY_SIGNAL,
605 TPL_NOTIFY,
606 BiosVideoNotifyExitBootServices,
607 BiosVideoPrivate,
608 &gEfiEventExitBootServicesGuid,
609 &BiosVideoPrivate->ExitBootServicesEvent
610 );
611 if (EFI_ERROR (Status)) {
612 goto Done;
613 }
614 }
615
616 //
617 // Initialize the child private structure
618 //
619 BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
620
621 //
622 // Fill in Graphics Output specific mode structures
623 //
624 BiosVideoPrivate->HardwareNeedsStarting = TRUE;
625 BiosVideoPrivate->ModeData = NULL;
626 BiosVideoPrivate->LineBuffer = NULL;
627 BiosVideoPrivate->VgaFrameBuffer = NULL;
628 BiosVideoPrivate->VbeFrameBuffer = NULL;
629
630 //
631 // Fill in the Graphics Output Protocol
632 //
633 BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
634 BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode;
635
636
637 //
638 // Allocate buffer for Graphics Output Protocol mode information
639 //
640 BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
641 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
642 );
643 if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {
644 Status = EFI_OUT_OF_RESOURCES;
645 goto Done;
646 }
647
648 BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
649 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
650 );
651 if (NULL == BiosVideoPrivate->GraphicsOutput.Mode->Info) {
652 Status = EFI_OUT_OF_RESOURCES;
653 goto Done;
654 }
655
656 //
657 // Assume that Graphics Output Protocol will be produced until proven otherwise
658 //
659 BiosVideoPrivate->ProduceGraphicsOutput = TRUE;
660
661 //
662 // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
663 //
664 if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
665 if (RemainingDevicePath == NULL) {
666 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
667 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
668 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
669 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
670 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
671
672 BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (
673 ParentDevicePath,
674 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
675 );
676 } else {
677 BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
678 }
679
680 //
681 // Creat child handle and device path protocol firstly
682 //
683 BiosVideoPrivate->Handle = NULL;
684 Status = gBS->InstallMultipleProtocolInterfaces (
685 &BiosVideoPrivate->Handle,
686 &gEfiDevicePathProtocolGuid,
687 BiosVideoPrivate->GopDevicePath,
688 NULL
689 );
690 if (EFI_ERROR (Status)) {
691 goto Done;
692 }
693 }
694
695 //
696 // Fill in the VGA Mini Port Protocol fields
697 //
698 BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode;
699 BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
700 BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
701 BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
702 BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
703 BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
704 BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
705
706 //
707 // Child handle need to consume the Legacy Bios protocol
708 //
709 BiosVideoPrivate->LegacyBios = ParentLegacyBios;
710
711 //
712 // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
713 //
714 BiosVideoPrivate->PciIo = ParentPciIo;
715
716 //
717 // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
718 //
719 if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {
720 Status = BiosVideoCheckForVbe (BiosVideoPrivate);
721 DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));
722 } else {
723 Status = EFI_UNSUPPORTED;
724 }
725 if (EFI_ERROR (Status)) {
726 //
727 // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
728 // for the standard 640x480 16 color VGA mode
729 //
730 DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));
731 if (BiosVideoPrivate->VgaCompatible) {
732 if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {
733 Status = BiosVideoCheckForVga (BiosVideoPrivate);
734 DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));
735 } else {
736 Status = EFI_UNSUPPORTED;
737 }
738 }
739
740 if (EFI_ERROR (Status)) {
741 //
742 // Free GOP mode structure if it is not freed before
743 // VgaMiniPort does not need this structure any more
744 //
745 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
746 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
747 FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
748 BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
749 }
750 FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
751 BiosVideoPrivate->GraphicsOutput.Mode = NULL;
752 }
753
754 //
755 // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
756 // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
757 //
758 BiosVideoPrivate->ProduceGraphicsOutput = FALSE;
759
760 //
761 // INT services are available, so on the 80x25 and 80x50 text mode are supported
762 //
763 BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
764 }
765 }
766
767 ProtocolInstalled = FALSE;
768
769 if (BiosVideoPrivate->ProduceGraphicsOutput) {
770 //
771 // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
772 //
773 Status = gBS->InstallMultipleProtocolInterfaces (
774 &BiosVideoPrivate->Handle,
775 &gEfiGraphicsOutputProtocolGuid,
776 &BiosVideoPrivate->GraphicsOutput,
777 &gEfiEdidDiscoveredProtocolGuid,
778 &BiosVideoPrivate->EdidDiscovered,
779 &gEfiEdidActiveProtocolGuid,
780 &BiosVideoPrivate->EdidActive,
781 NULL
782 );
783
784 if (!EFI_ERROR (Status)) {
785 //
786 // Open the Parent Handle for the child
787 //
788 Status = gBS->OpenProtocol (
789 ParentHandle,
790 &gEfiPciIoProtocolGuid,
791 (VOID **) &BiosVideoPrivate->PciIo,
792 This->DriverBindingHandle,
793 BiosVideoPrivate->Handle,
794 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
795 );
796 if (EFI_ERROR (Status)) {
797 goto Done;
798 }
799 ProtocolInstalled = TRUE;
800 }
801 }
802
803 if (!ProtocolInstalled) {
804 //
805 // Install VGA Mini Port Protocol
806 //
807 Status = gBS->InstallMultipleProtocolInterfaces (
808 &ParentHandle,
809 &gEfiVgaMiniPortProtocolGuid,
810 &BiosVideoPrivate->VgaMiniPort,
811 NULL
812 );
813 }
814
815 Done:
816 if (EFI_ERROR (Status)) {
817 if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {
818 gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
819 }
820 //
821 // Free private data structure
822 //
823 BiosVideoDeviceReleaseResource (BiosVideoPrivate);
824 }
825
826 return Status;
827 }
828
829
830 /**
831 Deregister an video child handle and free resources.
832
833 @param This Protocol instance pointer.
834 @param Controller Video controller handle
835 @param Handle Video child handle
836
837 @return EFI_STATUS
838
839 **/
840 EFI_STATUS
841 BiosVideoChildHandleUninstall (
842 EFI_DRIVER_BINDING_PROTOCOL *This,
843 EFI_HANDLE Controller,
844 EFI_HANDLE Handle
845 )
846 {
847 EFI_STATUS Status;
848 EFI_IA32_REGISTER_SET Regs;
849 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
850 EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
851 BIOS_VIDEO_DEV *BiosVideoPrivate;
852 EFI_PCI_IO_PROTOCOL *PciIo;
853
854 BiosVideoPrivate = NULL;
855 GraphicsOutput = NULL;
856 PciIo = NULL;
857 Status = EFI_UNSUPPORTED;
858
859 Status = gBS->OpenProtocol (
860 Handle,
861 &gEfiGraphicsOutputProtocolGuid,
862 (VOID **) &GraphicsOutput,
863 This->DriverBindingHandle,
864 Handle,
865 EFI_OPEN_PROTOCOL_GET_PROTOCOL
866 );
867 if (!EFI_ERROR (Status)) {
868 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
869 }
870
871 if (EFI_ERROR (Status)) {
872 Status = gBS->OpenProtocol (
873 Handle,
874 &gEfiVgaMiniPortProtocolGuid,
875 (VOID **) &VgaMiniPort,
876 This->DriverBindingHandle,
877 Handle,
878 EFI_OPEN_PROTOCOL_GET_PROTOCOL
879 );
880 if (!EFI_ERROR (Status)) {
881 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
882 }
883 }
884
885 if (BiosVideoPrivate == NULL) {
886 return EFI_UNSUPPORTED;
887 }
888
889 //
890 // Set the 80x25 Text VGA Mode
891 //
892 Regs.H.AH = 0x00;
893 Regs.H.AL = 0x03;
894 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
895
896 Regs.H.AH = 0x11;
897 Regs.H.AL = 0x14;
898 Regs.H.BL = 0;
899 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
900
901 //
902 // Close PCI I/O protocol that opened by child handle
903 //
904 Status = gBS->CloseProtocol (
905 Controller,
906 &gEfiPciIoProtocolGuid,
907 This->DriverBindingHandle,
908 Handle
909 );
910
911 //
912 // Uninstall protocols on child handle
913 //
914 if (BiosVideoPrivate->ProduceGraphicsOutput) {
915 Status = gBS->UninstallMultipleProtocolInterfaces (
916 BiosVideoPrivate->Handle,
917 &gEfiDevicePathProtocolGuid,
918 BiosVideoPrivate->GopDevicePath,
919 &gEfiGraphicsOutputProtocolGuid,
920 &BiosVideoPrivate->GraphicsOutput,
921 &gEfiEdidDiscoveredProtocolGuid,
922 &BiosVideoPrivate->EdidDiscovered,
923 &gEfiEdidActiveProtocolGuid,
924 &BiosVideoPrivate->EdidActive,
925 NULL
926 );
927 }
928 if (!BiosVideoPrivate->ProduceGraphicsOutput) {
929 Status = gBS->UninstallMultipleProtocolInterfaces (
930 Controller,
931 &gEfiVgaMiniPortProtocolGuid,
932 &BiosVideoPrivate->VgaMiniPort,
933 NULL
934 );
935 }
936
937 if (EFI_ERROR (Status)) {
938 gBS->OpenProtocol (
939 Controller,
940 &gEfiPciIoProtocolGuid,
941 (VOID **) &PciIo,
942 This->DriverBindingHandle,
943 Handle,
944 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
945 );
946 return Status;
947 }
948
949 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
950 //
951 // Close EXIT_BOOT_SERIVES Event
952 //
953 gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
954 }
955
956 //
957 // Release all allocated resources
958 //
959 BiosVideoDeviceReleaseResource (BiosVideoPrivate);
960
961 return EFI_SUCCESS;
962 }
963
964
965 /**
966 Release resource for biso video instance.
967
968 @param BiosVideoPrivate Video child device private data structure
969
970 **/
971 VOID
972 BiosVideoDeviceReleaseResource (
973 BIOS_VIDEO_DEV *BiosVideoPrivate
974 )
975 {
976 if (BiosVideoPrivate == NULL) {
977 return ;
978 }
979
980 //
981 // Release all the resourses occupied by the BIOS_VIDEO_DEV
982 //
983
984 //
985 // Free VGA Frame Buffer
986 //
987 if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
988 FreePool (BiosVideoPrivate->VgaFrameBuffer);
989 }
990 //
991 // Free VBE Frame Buffer
992 //
993 if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
994 FreePool (BiosVideoPrivate->VbeFrameBuffer);
995 }
996 //
997 // Free line buffer
998 //
999 if (BiosVideoPrivate->LineBuffer != NULL) {
1000 FreePool (BiosVideoPrivate->LineBuffer);
1001 }
1002 //
1003 // Free mode data
1004 //
1005 if (BiosVideoPrivate->ModeData != NULL) {
1006 FreePool (BiosVideoPrivate->ModeData);
1007 }
1008 //
1009 // Free memory allocated below 1MB
1010 //
1011 if (BiosVideoPrivate->PagesBelow1MB != 0) {
1012 gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
1013 }
1014
1015 if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
1016 gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
1017 }
1018
1019 //
1020 // Free graphics output protocol occupied resource
1021 //
1022 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1023 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1024 FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1025 BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1026 }
1027 FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1028 BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1029 }
1030 //
1031 // Free EDID discovered protocol occupied resource
1032 //
1033 if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {
1034 FreePool (BiosVideoPrivate->EdidDiscovered.Edid);
1035 }
1036 //
1037 // Free EDID active protocol occupied resource
1038 //
1039 if (BiosVideoPrivate->EdidActive.Edid != NULL) {
1040 FreePool (BiosVideoPrivate->EdidActive.Edid);
1041 }
1042
1043 if (BiosVideoPrivate->GopDevicePath!= NULL) {
1044 FreePool (BiosVideoPrivate->GopDevicePath);
1045 }
1046
1047 FreePool (BiosVideoPrivate);
1048
1049 return ;
1050 }
1051
1052
1053 /**
1054 Generate a search key for a specified timing data.
1055
1056 @param EdidTiming Pointer to EDID timing
1057
1058 @return The 32 bit unique key for search.
1059
1060 **/
1061 UINT32
1062 CalculateEdidKey (
1063 VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
1064 )
1065 {
1066 UINT32 Key;
1067
1068 //
1069 // Be sure no conflicts for all standard timing defined by VESA.
1070 //
1071 Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
1072 return Key;
1073 }
1074
1075
1076 /**
1077 Parse the Established Timing and Standard Timing in EDID data block.
1078
1079 @param EdidBuffer Pointer to EDID data block
1080 @param ValidEdidTiming Valid EDID timing information
1081
1082 @retval TRUE The EDID data is valid.
1083 @retval FALSE The EDID data is invalid.
1084
1085 **/
1086 BOOLEAN
1087 ParseEdidData (
1088 UINT8 *EdidBuffer,
1089 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming
1090 )
1091 {
1092 UINT8 CheckSum;
1093 UINT32 Index;
1094 UINT32 ValidNumber;
1095 UINT32 TimingBits;
1096 UINT8 *BufferIndex;
1097 UINT16 HorizontalResolution;
1098 UINT16 VerticalResolution;
1099 UINT8 AspectRatio;
1100 UINT8 RefreshRate;
1101 VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming;
1102 VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
1103
1104 EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;
1105
1106 //
1107 // Check the checksum of EDID data
1108 //
1109 CheckSum = 0;
1110 for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {
1111 CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
1112 }
1113 if (CheckSum != 0) {
1114 return FALSE;
1115 }
1116
1117 ValidNumber = 0;
1118 gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);
1119
1120 if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
1121 (EdidDataBlock->EstablishedTimings[1] != 0) ||
1122 (EdidDataBlock->EstablishedTimings[2] != 0)
1123 ) {
1124 //
1125 // Established timing data
1126 //
1127 TimingBits = EdidDataBlock->EstablishedTimings[0] |
1128 (EdidDataBlock->EstablishedTimings[1] << 8) |
1129 ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
1130 for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
1131 if ((TimingBits & 0x1) != 0) {
1132 DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n",
1133 mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution));
1134 ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);
1135 ValidNumber ++;
1136 }
1137 TimingBits = TimingBits >> 1;
1138 }
1139 }
1140
1141 //
1142 // Parse the standard timing data
1143 //
1144 BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
1145 for (Index = 0; Index < 8; Index ++) {
1146 //
1147 // Check if this is a valid Standard Timing entry
1148 // VESA documents unused fields should be set to 01h
1149 //
1150 if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
1151 //
1152 // A valid Standard Timing
1153 //
1154 HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
1155 AspectRatio = (UINT8) (BufferIndex[1] >> 6);
1156 switch (AspectRatio) {
1157 case 0:
1158 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
1159 break;
1160 case 1:
1161 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
1162 break;
1163 case 2:
1164 VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
1165 break;
1166 case 3:
1167 VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
1168 break;
1169 default:
1170 VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
1171 break;
1172 }
1173 RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
1174 DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution));
1175 TempTiming.HorizontalResolution = HorizontalResolution;
1176 TempTiming.VerticalResolution = VerticalResolution;
1177 TempTiming.RefreshRate = RefreshRate;
1178 ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
1179 ValidNumber ++;
1180 }
1181 BufferIndex += 2;
1182 }
1183
1184 //
1185 // Parse the Detailed Timing data
1186 //
1187 BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0];
1188 for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) {
1189 if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) {
1190 //
1191 // Check if this is a valid Detailed Timing Descriptor
1192 // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor
1193 //
1194 continue;
1195 }
1196 //
1197 // Calculate Horizontal and Vertical resolution
1198 //
1199 TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]);
1200 TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]);
1201 DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n",
1202 Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution));
1203 ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
1204 ValidNumber ++;
1205 }
1206
1207 ValidEdidTiming->ValidNumber = ValidNumber;
1208 return TRUE;
1209 }
1210
1211
1212 /**
1213 Search a specified Timing in all the valid EDID timings.
1214
1215 @param ValidEdidTiming All valid EDID timing information.
1216 @param EdidTiming The Timing to search for.
1217
1218 @retval TRUE Found.
1219 @retval FALSE Not found.
1220
1221 **/
1222 BOOLEAN
1223 SearchEdidTiming (
1224 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,
1225 VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
1226 )
1227 {
1228 UINT32 Index;
1229 UINT32 Key;
1230
1231 Key = CalculateEdidKey (EdidTiming);
1232
1233 for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
1234 if (Key == ValidEdidTiming->Key[Index]) {
1235 return TRUE;
1236 }
1237 }
1238
1239 return FALSE;
1240 }
1241
1242 /**
1243 Check if all video child handles have been uninstalled.
1244
1245 @param Controller Video controller handle
1246
1247 @return TRUE Child handles exist.
1248 @return FALSE All video child handles have been uninstalled.
1249
1250 **/
1251 BOOLEAN
1252 HasChildHandle (
1253 IN EFI_HANDLE Controller
1254 )
1255 {
1256 UINTN Index;
1257 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
1258 UINTN EntryCount;
1259 BOOLEAN HasChild;
1260
1261 EntryCount = 0;
1262 HasChild = FALSE;
1263 gBS->OpenProtocolInformation (
1264 Controller,
1265 &gEfiPciIoProtocolGuid,
1266 &OpenInfoBuffer,
1267 &EntryCount
1268 );
1269 for (Index = 0; Index < EntryCount; Index++) {
1270 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1271 HasChild = TRUE;
1272 }
1273 }
1274
1275 return HasChild;
1276 }
1277
1278 /**
1279 Check for VBE device.
1280
1281 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1282
1283 @retval EFI_SUCCESS VBE device found
1284
1285 **/
1286 EFI_STATUS
1287 BiosVideoCheckForVbe (
1288 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1289 )
1290 {
1291 EFI_STATUS Status;
1292 EFI_IA32_REGISTER_SET Regs;
1293 UINT16 *ModeNumberPtr;
1294 UINT16 VbeModeNumber;
1295 BOOLEAN ModeFound;
1296 BOOLEAN EdidFound;
1297 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1298 BIOS_VIDEO_MODE_DATA *CurrentModeData;
1299 UINTN PreferMode;
1300 UINTN ModeNumber;
1301 VESA_BIOS_EXTENSIONS_EDID_TIMING Timing;
1302 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
1303 EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
1304 UINT32 EdidAttributes;
1305 BOOLEAN EdidOverrideFound;
1306 UINTN EdidOverrideDataSize;
1307 UINT8 *EdidOverrideDataBlock;
1308 UINTN EdidActiveDataSize;
1309 UINT8 *EdidActiveDataBlock;
1310 UINT32 HighestHorizontalResolution;
1311 UINT32 HighestVerticalResolution;
1312 UINTN HighestResolutionMode;
1313
1314 EdidFound = TRUE;
1315 EdidOverrideFound = FALSE;
1316 EdidOverrideDataBlock = NULL;
1317 EdidActiveDataSize = 0;
1318 EdidActiveDataBlock = NULL;
1319 HighestHorizontalResolution = 0;
1320 HighestVerticalResolution = 0;
1321 HighestResolutionMode = 0;
1322
1323 //
1324 // Allocate buffer under 1MB for VBE data structures
1325 //
1326 BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
1327 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
1328 sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
1329 sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
1330 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
1331 );
1332
1333 BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
1334
1335 Status = gBS->AllocatePages (
1336 AllocateMaxAddress,
1337 EfiBootServicesData,
1338 BiosVideoPrivate->NumberOfPagesBelow1MB,
1339 &BiosVideoPrivate->PagesBelow1MB
1340 );
1341 if (EFI_ERROR (Status)) {
1342 return Status;
1343 }
1344
1345 ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
1346
1347 //
1348 // Fill in the VBE related data structures
1349 //
1350 BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
1351 BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
1352 BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
1353 BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
1354 BiosVideoPrivate->VbeSaveRestorePages = 0;
1355 BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
1356
1357 //
1358 // Test to see if the Video Adapter is compliant with VBE 3.0
1359 //
1360 gBS->SetMem (&Regs, sizeof (Regs), 0);
1361 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
1362 gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
1363 BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
1364 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1365 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1366
1367 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1368
1369 Status = EFI_DEVICE_ERROR;
1370
1371 //
1372 // See if the VESA call succeeded
1373 //
1374 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1375 return Status;
1376 }
1377 //
1378 // Check for 'VESA' signature
1379 //
1380 if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
1381 return Status;
1382 }
1383 //
1384 // Check to see if this is VBE 2.0 or higher
1385 //
1386 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
1387 return Status;
1388 }
1389
1390 EdidFound = FALSE;
1391 EdidAttributes = 0xff;
1392 EdidOverrideDataSize = 0;
1393
1394 //
1395 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1396 //
1397 Status = gBS->LocateProtocol (
1398 &gEfiEdidOverrideProtocolGuid,
1399 NULL,
1400 (VOID **) &EdidOverride
1401 );
1402 if (!EFI_ERROR (Status)) {
1403 //
1404 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1405 //
1406 EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);
1407 if (NULL == EdidOverrideDataBlock) {
1408 Status = EFI_OUT_OF_RESOURCES;
1409 goto Done;
1410 }
1411
1412 Status = EdidOverride->GetEdid (
1413 EdidOverride,
1414 BiosVideoPrivate->Handle,
1415 &EdidAttributes,
1416 &EdidOverrideDataSize,
1417 (UINT8 **) &EdidOverrideDataBlock
1418 );
1419 if (!EFI_ERROR (Status) &&
1420 EdidAttributes == 0 &&
1421 EdidOverrideDataSize != 0) {
1422 //
1423 // Succeeded to get EDID Override Data
1424 //
1425 EdidOverrideFound = TRUE;
1426 }
1427 }
1428
1429 if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
1430 //
1431 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1432 // read EDID information through INT10 call
1433 //
1434
1435 gBS->SetMem (&Regs, sizeof (Regs), 0);
1436 Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
1437 Regs.X.BX = 1;
1438 Regs.X.CX = 0;
1439 Regs.X.DX = 0;
1440 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1441 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1442
1443 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1444 //
1445 // See if the VESA call succeeded
1446 //
1447 if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1448 //
1449 // Set EDID Discovered Data
1450 //
1451 BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1452 BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
1453 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1454 BiosVideoPrivate->VbeEdidDataBlock
1455 );
1456
1457 if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
1458 Status = EFI_OUT_OF_RESOURCES;
1459 goto Done;
1460 }
1461
1462 EdidFound = TRUE;
1463 }
1464 }
1465
1466 if (EdidFound) {
1467 EdidActiveDataSize = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1468 EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
1469 } else if (EdidOverrideFound) {
1470 EdidActiveDataSize = EdidOverrideDataSize;
1471 EdidActiveDataBlock = EdidOverrideDataBlock;
1472 EdidFound = TRUE;
1473 }
1474
1475 if (EdidFound) {
1476 //
1477 // Parse EDID data structure to retrieve modes supported by monitor
1478 //
1479 if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
1480 //
1481 // Copy EDID Override Data to EDID Active Data
1482 //
1483 BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
1484 BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
1485 EdidActiveDataSize,
1486 EdidActiveDataBlock
1487 );
1488 if (NULL == BiosVideoPrivate->EdidActive.Edid) {
1489 Status = EFI_OUT_OF_RESOURCES;
1490 goto Done;
1491 }
1492 }
1493 } else {
1494 BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
1495 BiosVideoPrivate->EdidActive.Edid = NULL;
1496 EdidFound = FALSE;
1497 }
1498
1499 //
1500 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1501 //
1502 ModeNumberPtr = (UINT16 *)
1503 (
1504 (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
1505 ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
1506 );
1507
1508 PreferMode = 0;
1509 ModeNumber = 0;
1510
1511 //
1512 // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1513 //
1514 for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);
1515 VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;
1516 VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {
1517 //
1518 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1519 //
1520 if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
1521 continue;
1522 }
1523 //
1524 // Get the information about the mode
1525 //
1526 gBS->SetMem (&Regs, sizeof (Regs), 0);
1527 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
1528 Regs.X.CX = VbeModeNumber;
1529 gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
1530 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1531 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1532
1533 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1534
1535 //
1536 // See if the call succeeded. If it didn't, then try the next mode.
1537 //
1538 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1539 continue;
1540 }
1541 //
1542 // See if the mode supports color. If it doesn't then try the next mode.
1543 //
1544 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
1545 continue;
1546 }
1547 //
1548 // See if the mode supports graphics. If it doesn't then try the next mode.
1549 //
1550 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
1551 continue;
1552 }
1553 //
1554 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1555 //
1556 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
1557 continue;
1558 }
1559 //
1560 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1561 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1562 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1563 //
1564 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
1565 continue;
1566 }
1567
1568 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
1569 continue;
1570 }
1571
1572 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
1573 continue;
1574 }
1575 //
1576 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1577 //
1578 if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
1579 continue;
1580 }
1581
1582 DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",
1583 VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));
1584
1585 if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
1586 //
1587 // EDID exist, check whether this mode match with any mode in EDID
1588 //
1589 Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1590 Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1591 if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
1592 //
1593 // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1594 // but INT10 can support these modes, we add them into GOP mode.
1595 //
1596 if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&
1597 !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&
1598 !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&
1599 !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {
1600 continue;
1601 }
1602 }
1603 }
1604
1605 //
1606 // Select a reasonable mode to be set for current display mode
1607 //
1608 ModeFound = FALSE;
1609
1610 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
1611 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
1612 ) {
1613 ModeFound = TRUE;
1614 }
1615 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
1616 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
1617 ) {
1618 ModeFound = TRUE;
1619 PreferMode = ModeNumber;
1620 }
1621 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
1622 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
1623 ) {
1624 ModeFound = TRUE;
1625 }
1626
1627 if ((!EdidFound) && (!ModeFound)) {
1628 //
1629 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1630 //
1631 continue;
1632 }
1633
1634 //
1635 // Record the highest resolution mode to set later
1636 //
1637 if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||
1638 ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&
1639 (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {
1640 HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1641 HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1642 HighestResolutionMode = ModeNumber;
1643 }
1644
1645 //
1646 // Add mode to the list of available modes
1647 //
1648 ModeNumber ++;
1649 ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1650 ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
1651 );
1652 if (NULL == ModeBuffer) {
1653 Status = EFI_OUT_OF_RESOURCES;
1654 goto Done;
1655 }
1656
1657 if (ModeNumber > 1) {
1658 CopyMem (
1659 ModeBuffer,
1660 BiosVideoPrivate->ModeData,
1661 (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1662 );
1663 }
1664
1665 if (BiosVideoPrivate->ModeData != NULL) {
1666 FreePool (BiosVideoPrivate->ModeData);
1667 }
1668
1669 CurrentModeData = &ModeBuffer[ModeNumber - 1];
1670 CurrentModeData->VbeModeNumber = VbeModeNumber;
1671 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
1672 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
1673 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
1674 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
1675 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
1676 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
1677 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
1678 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
1679 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
1680 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
1681 } else {
1682 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1683 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1684 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1685 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1686 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1687 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1688 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1689 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
1690 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
1691 }
1692
1693 CurrentModeData->PixelFormat = PixelBitMask;
1694 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
1695 (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
1696 if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
1697 CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
1698 } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
1699 CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
1700 }
1701 }
1702
1703 CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
1704 CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
1705 CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
1706 CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
1707
1708 CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1709 CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1710 CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1711
1712 CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1713 CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
1714 //
1715 // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1716 //
1717 ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));
1718
1719 BiosVideoPrivate->ModeData = ModeBuffer;
1720 }
1721 //
1722 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1723 //
1724 if (ModeNumber == 0) {
1725 Status = EFI_DEVICE_ERROR;
1726 goto Done;
1727 }
1728
1729 //
1730 // Assign Gop's Blt function
1731 //
1732 BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt;
1733
1734 BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
1735 //
1736 // Current mode is unknow till now, set it to an invalid mode.
1737 //
1738 BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1739
1740 //
1741 // Find the best mode to initialize
1742 //
1743 if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {
1744 DEBUG_CODE (
1745 BIOS_VIDEO_MODE_DATA *ModeData;
1746 ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];
1747 DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",
1748 ModeData->HorizontalResolution, ModeData->VerticalResolution));
1749 );
1750 PreferMode = HighestResolutionMode;
1751 }
1752 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
1753 if (EFI_ERROR (Status)) {
1754 for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
1755 Status = BiosVideoGraphicsOutputSetMode (
1756 &BiosVideoPrivate->GraphicsOutput,
1757 (UINT32) PreferMode
1758 );
1759 if (!EFI_ERROR (Status)) {
1760 break;
1761 }
1762 }
1763 if (PreferMode == ModeNumber) {
1764 //
1765 // None mode is set successfully.
1766 //
1767 goto Done;
1768 }
1769 }
1770
1771 Done:
1772 //
1773 // If there was an error, then free the mode structure
1774 //
1775 if (EFI_ERROR (Status)) {
1776 if (BiosVideoPrivate->ModeData != NULL) {
1777 FreePool (BiosVideoPrivate->ModeData);
1778 BiosVideoPrivate->ModeData = NULL;
1779 BiosVideoPrivate->MaxMode = 0;
1780 }
1781 if (EdidOverrideDataBlock != NULL) {
1782 FreePool (EdidOverrideDataBlock);
1783 }
1784 }
1785
1786 return Status;
1787 }
1788
1789
1790 /**
1791 Check for VGA device.
1792
1793 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1794
1795 @retval EFI_SUCCESS Standard VGA device found
1796
1797 **/
1798 EFI_STATUS
1799 BiosVideoCheckForVga (
1800 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1801 )
1802 {
1803 EFI_STATUS Status;
1804 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1805
1806 Status = EFI_UNSUPPORTED;
1807
1808 //
1809 // Assign Gop's Blt function
1810 //
1811 BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt;
1812
1813 //
1814 // Add mode to the list of available modes
1815 // caller should guarantee that Mode has been allocated.
1816 //
1817 ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
1818 BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
1819
1820 ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1821 sizeof (BIOS_VIDEO_MODE_DATA)
1822 );
1823 if (NULL == ModeBuffer) {
1824 Status = EFI_OUT_OF_RESOURCES;
1825 goto Done;
1826 }
1827
1828 ModeBuffer->VbeModeNumber = 0x0012;
1829 ModeBuffer->BytesPerScanLine = 640;
1830 ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000);
1831 ModeBuffer->HorizontalResolution = 640;
1832 ModeBuffer->VerticalResolution = 480;
1833 ModeBuffer->PixelFormat = PixelBltOnly;
1834 ModeBuffer->BitsPerPixel = 8;
1835 ModeBuffer->ColorDepth = 32;
1836 ModeBuffer->RefreshRate = 60;
1837
1838 BiosVideoPrivate->ModeData = ModeBuffer;
1839
1840 //
1841 // Test to see if the Video Adapter support the 640x480 16 color mode
1842 //
1843 BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1844 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
1845
1846 Done:
1847 //
1848 // If there was an error, then free the mode structure
1849 //
1850 if (EFI_ERROR (Status)) {
1851 if (BiosVideoPrivate->ModeData != NULL) {
1852 FreePool (BiosVideoPrivate->ModeData);
1853 BiosVideoPrivate->ModeData = NULL;
1854 }
1855 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1856 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1857 FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1858 BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1859 }
1860 FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1861 BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1862 }
1863 }
1864 return Status;
1865 }
1866
1867 //
1868 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1869 //
1870
1871 /**
1872 Graphics Output protocol interface to get video mode.
1873
1874 @param This Protocol instance pointer.
1875 @param ModeNumber The mode number to return information on.
1876 @param SizeOfInfo A pointer to the size, in bytes, of the Info
1877 buffer.
1878 @param Info Caller allocated buffer that returns information
1879 about ModeNumber.
1880
1881 @retval EFI_SUCCESS Mode information returned.
1882 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
1883 video mode.
1884 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
1885 @retval EFI_INVALID_PARAMETER One of the input args was NULL.
1886
1887 **/
1888 EFI_STATUS
1889 EFIAPI
1890 BiosVideoGraphicsOutputQueryMode (
1891 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
1892 IN UINT32 ModeNumber,
1893 OUT UINTN *SizeOfInfo,
1894 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
1895 )
1896 {
1897 BIOS_VIDEO_DEV *BiosVideoPrivate;
1898 BIOS_VIDEO_MODE_DATA *ModeData;
1899
1900 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1901
1902 if (BiosVideoPrivate->HardwareNeedsStarting) {
1903 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1904 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1905 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
1906 BiosVideoPrivate->GopDevicePath
1907 );
1908 return EFI_NOT_STARTED;
1909 }
1910
1911 if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
1912 return EFI_INVALID_PARAMETER;
1913 }
1914
1915 *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
1916 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
1917 );
1918 if (NULL == *Info) {
1919 return EFI_OUT_OF_RESOURCES;
1920 }
1921
1922 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1923
1924 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1925 (*Info)->Version = 0;
1926 (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
1927 (*Info)->VerticalResolution = ModeData->VerticalResolution;
1928 (*Info)->PixelFormat = ModeData->PixelFormat;
1929 CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
1930
1931 (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1932
1933 return EFI_SUCCESS;
1934 }
1935
1936 /**
1937 Worker function to set video mode.
1938
1939 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
1940 @param ModeData The mode data to be set.
1941 @param DevicePath Pointer to Device Path Protocol.
1942
1943 @retval EFI_SUCCESS Graphics mode was changed.
1944 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1945 request.
1946 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
1947
1948 **/
1949 EFI_STATUS
1950 BiosVideoSetModeWorker (
1951 IN BIOS_VIDEO_DEV *BiosVideoPrivate,
1952 IN BIOS_VIDEO_MODE_DATA *ModeData,
1953 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1954 )
1955 {
1956 EFI_STATUS Status;
1957 EFI_IA32_REGISTER_SET Regs;
1958
1959 if (BiosVideoPrivate->LineBuffer != NULL) {
1960 FreePool (BiosVideoPrivate->LineBuffer);
1961 }
1962
1963 if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
1964 FreePool (BiosVideoPrivate->VgaFrameBuffer);
1965 }
1966
1967 if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
1968 FreePool (BiosVideoPrivate->VbeFrameBuffer);
1969 }
1970
1971 BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
1972 ModeData->BytesPerScanLine
1973 );
1974 if (NULL == BiosVideoPrivate->LineBuffer) {
1975 return EFI_OUT_OF_RESOURCES;
1976 }
1977 //
1978 // Clear all registers
1979 //
1980 ZeroMem (&Regs, sizeof (Regs));
1981
1982 if (ModeData->VbeModeNumber < 0x100) {
1983 //
1984 // Allocate a working buffer for BLT operations to the VGA frame buffer
1985 //
1986 BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
1987 if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
1988 return EFI_OUT_OF_RESOURCES;
1989 }
1990 //
1991 // Set VGA Mode
1992 //
1993 Regs.X.AX = ModeData->VbeModeNumber;
1994 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1995
1996 } else {
1997 //
1998 // Allocate a working buffer for BLT operations to the VBE frame buffer
1999 //
2000 BiosVideoPrivate->VbeFrameBuffer =
2001 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
2002 ModeData->BytesPerScanLine * ModeData->VerticalResolution
2003 );
2004 if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
2005 return EFI_OUT_OF_RESOURCES;
2006 }
2007 //
2008 // Set VBE mode
2009 //
2010 Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
2011 Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
2012 ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
2013 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2014 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2015 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
2016
2017 //
2018 // Check to see if the call succeeded
2019 //
2020 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
2021 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2022 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2023 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
2024 DevicePath
2025 );
2026 return EFI_DEVICE_ERROR;
2027 }
2028 //
2029 // Initialize the state of the VbeFrameBuffer
2030 //
2031 Status = BiosVideoPrivate->PciIo->Mem.Read (
2032 BiosVideoPrivate->PciIo,
2033 EfiPciIoWidthUint32,
2034 EFI_PCI_IO_PASS_THROUGH_BAR,
2035 (UINT64) (UINTN) ModeData->LinearFrameBuffer,
2036 (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
2037 BiosVideoPrivate->VbeFrameBuffer
2038 );
2039 if (EFI_ERROR (Status)) {
2040 return Status;
2041 }
2042 }
2043
2044 return EFI_SUCCESS;
2045 }
2046
2047 /**
2048 Graphics Output protocol interface to set video mode.
2049
2050 @param This Protocol instance pointer.
2051 @param ModeNumber The mode number to be set.
2052
2053 @retval EFI_SUCCESS Graphics mode was changed.
2054 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
2055 request.
2056 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
2057
2058 **/
2059 EFI_STATUS
2060 EFIAPI
2061 BiosVideoGraphicsOutputSetMode (
2062 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
2063 IN UINT32 ModeNumber
2064 )
2065 {
2066 EFI_STATUS Status;
2067 BIOS_VIDEO_DEV *BiosVideoPrivate;
2068 BIOS_VIDEO_MODE_DATA *ModeData;
2069 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
2070
2071 if (This == NULL) {
2072 return EFI_INVALID_PARAMETER;
2073 }
2074
2075 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2076
2077 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
2078
2079 if (ModeNumber >= This->Mode->MaxMode) {
2080 return EFI_UNSUPPORTED;
2081 }
2082
2083 if (ModeNumber == This->Mode->Mode) {
2084 //
2085 // Clear screen to black
2086 //
2087 ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2088 BiosVideoGraphicsOutputVbeBlt (
2089 This,
2090 &Background,
2091 EfiBltVideoFill,
2092 0,
2093 0,
2094 0,
2095 0,
2096 ModeData->HorizontalResolution,
2097 ModeData->VerticalResolution,
2098 0
2099 );
2100 return EFI_SUCCESS;
2101 }
2102
2103 Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
2104 if (EFI_ERROR (Status)) {
2105 return Status;
2106 }
2107
2108 This->Mode->Mode = ModeNumber;
2109 This->Mode->Info->Version = 0;
2110 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
2111 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
2112 This->Mode->Info->PixelFormat = ModeData->PixelFormat;
2113 CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
2114 This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
2115 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
2116 This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
2117 This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
2118
2119 BiosVideoPrivate->HardwareNeedsStarting = FALSE;
2120
2121 return EFI_SUCCESS;
2122 }
2123
2124 /**
2125 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2126
2127 @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
2128 @param VbeBuffer The data to transfer to screen
2129 @param MemAddress Physical frame buffer base address
2130 @param DestinationX The X coordinate of the destination for BltOperation
2131 @param DestinationY The Y coordinate of the destination for BltOperation
2132 @param TotalBytes The total bytes of copy
2133 @param VbePixelWidth Bytes per pixel
2134 @param BytesPerScanLine Bytes per scan line
2135
2136 **/
2137 VOID
2138 CopyVideoBuffer (
2139 IN EFI_PCI_IO_PROTOCOL *PciIo,
2140 IN UINT8 *VbeBuffer,
2141 IN VOID *MemAddress,
2142 IN UINTN DestinationX,
2143 IN UINTN DestinationY,
2144 IN UINTN TotalBytes,
2145 IN UINT32 VbePixelWidth,
2146 IN UINTN BytesPerScanLine
2147 )
2148 {
2149 UINTN FrameBufferAddr;
2150 UINTN CopyBlockNum;
2151 UINTN RemainingBytes;
2152 UINTN UnalignedBytes;
2153 EFI_STATUS Status;
2154
2155 FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
2156
2157 //
2158 // If TotalBytes is less than 4 bytes, only start byte copy.
2159 //
2160 if (TotalBytes < 4) {
2161 Status = PciIo->Mem.Write (
2162 PciIo,
2163 EfiPciIoWidthUint8,
2164 EFI_PCI_IO_PASS_THROUGH_BAR,
2165 (UINT64) FrameBufferAddr,
2166 TotalBytes,
2167 VbeBuffer
2168 );
2169 ASSERT_EFI_ERROR (Status);
2170 return;
2171 }
2172
2173 //
2174 // If VbeBuffer is not 4-byte aligned, start byte copy.
2175 //
2176 UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
2177
2178 if (UnalignedBytes != 0) {
2179 Status = PciIo->Mem.Write (
2180 PciIo,
2181 EfiPciIoWidthUint8,
2182 EFI_PCI_IO_PASS_THROUGH_BAR,
2183 (UINT64) FrameBufferAddr,
2184 UnalignedBytes,
2185 VbeBuffer
2186 );
2187 ASSERT_EFI_ERROR (Status);
2188 FrameBufferAddr += UnalignedBytes;
2189 VbeBuffer += UnalignedBytes;
2190 }
2191
2192 //
2193 // Calculate 4-byte block count and remaining bytes.
2194 //
2195 CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
2196 RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
2197
2198 //
2199 // Copy 4-byte block and remaining bytes to physical frame buffer.
2200 //
2201 if (CopyBlockNum != 0) {
2202 Status = PciIo->Mem.Write (
2203 PciIo,
2204 EfiPciIoWidthUint32,
2205 EFI_PCI_IO_PASS_THROUGH_BAR,
2206 (UINT64) FrameBufferAddr,
2207 CopyBlockNum,
2208 VbeBuffer
2209 );
2210 ASSERT_EFI_ERROR (Status);
2211 }
2212
2213 if (RemainingBytes != 0) {
2214 FrameBufferAddr += (CopyBlockNum << 2);
2215 VbeBuffer += (CopyBlockNum << 2);
2216 Status = PciIo->Mem.Write (
2217 PciIo,
2218 EfiPciIoWidthUint8,
2219 EFI_PCI_IO_PASS_THROUGH_BAR,
2220 (UINT64) FrameBufferAddr,
2221 RemainingBytes,
2222 VbeBuffer
2223 );
2224 ASSERT_EFI_ERROR (Status);
2225 }
2226 }
2227
2228 /**
2229 Worker function to block transfer for VBE device.
2230
2231 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
2232 @param BltBuffer The data to transfer to screen
2233 @param BltOperation The operation to perform
2234 @param SourceX The X coordinate of the source for BltOperation
2235 @param SourceY The Y coordinate of the source for BltOperation
2236 @param DestinationX The X coordinate of the destination for
2237 BltOperation
2238 @param DestinationY The Y coordinate of the destination for
2239 BltOperation
2240 @param Width The width of a rectangle in the blt rectangle in
2241 pixels
2242 @param Height The height of a rectangle in the blt rectangle in
2243 pixels
2244 @param Delta Not used for EfiBltVideoFill and
2245 EfiBltVideoToVideo operation. If a Delta of 0 is
2246 used, the entire BltBuffer will be operated on. If
2247 a subrectangle of the BltBuffer is used, then
2248 Delta represents the number of bytes in a row of
2249 the BltBuffer.
2250 @param Mode Mode data.
2251
2252 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2253 @retval EFI_SUCCESS Blt operation success
2254
2255 **/
2256 EFI_STATUS
2257 BiosVideoVbeBltWorker (
2258 IN BIOS_VIDEO_DEV *BiosVideoPrivate,
2259 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2260 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2261 IN UINTN SourceX,
2262 IN UINTN SourceY,
2263 IN UINTN DestinationX,
2264 IN UINTN DestinationY,
2265 IN UINTN Width,
2266 IN UINTN Height,
2267 IN UINTN Delta,
2268 IN BIOS_VIDEO_MODE_DATA *Mode
2269 )
2270 {
2271 EFI_PCI_IO_PROTOCOL *PciIo;
2272 EFI_TPL OriginalTPL;
2273 UINTN DstY;
2274 UINTN SrcY;
2275 UINTN DstX;
2276 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
2277 VOID *MemAddress;
2278 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
2279 UINTN BytesPerScanLine;
2280 UINTN Index;
2281 UINT8 *VbeBuffer;
2282 UINT8 *VbeBuffer1;
2283 UINT8 *BltUint8;
2284 UINT32 VbePixelWidth;
2285 UINT32 Pixel;
2286 UINTN TotalBytes;
2287
2288 PciIo = BiosVideoPrivate->PciIo;
2289
2290 VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
2291 MemAddress = Mode->LinearFrameBuffer;
2292 BytesPerScanLine = Mode->BytesPerScanLine;
2293 VbePixelWidth = Mode->BitsPerPixel / 8;
2294 BltUint8 = (UINT8 *) BltBuffer;
2295 TotalBytes = Width * VbePixelWidth;
2296
2297 if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2298 return EFI_INVALID_PARAMETER;
2299 }
2300
2301 if (Width == 0 || Height == 0) {
2302 return EFI_INVALID_PARAMETER;
2303 }
2304 //
2305 // We need to fill the Virtual Screen buffer with the blt data.
2306 // The virtual screen is upside down, as the first row is the bootom row of
2307 // the image.
2308 //
2309 if (BltOperation == EfiBltVideoToBltBuffer) {
2310 //
2311 // Video to BltBuffer: Source is Video, destination is BltBuffer
2312 //
2313 if (SourceY + Height > Mode->VerticalResolution) {
2314 return EFI_INVALID_PARAMETER;
2315 }
2316
2317 if (SourceX + Width > Mode->HorizontalResolution) {
2318 return EFI_INVALID_PARAMETER;
2319 }
2320 } else {
2321 //
2322 // BltBuffer to Video: Source is BltBuffer, destination is Video
2323 //
2324 if (DestinationY + Height > Mode->VerticalResolution) {
2325 return EFI_INVALID_PARAMETER;
2326 }
2327
2328 if (DestinationX + Width > Mode->HorizontalResolution) {
2329 return EFI_INVALID_PARAMETER;
2330 }
2331 }
2332 //
2333 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2334 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2335 // the number of bytes in each row can be computed.
2336 //
2337 if (Delta == 0) {
2338 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2339 }
2340 //
2341 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2342 // We would not want a timer based event (Cursor, ...) to come in while we are
2343 // doing this operation.
2344 //
2345 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2346
2347 switch (BltOperation) {
2348 case EfiBltVideoToBltBuffer:
2349 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
2350 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2351 //
2352 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2353 //
2354 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
2355 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2356 Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
2357 Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
2358 Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
2359 Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
2360 Blt->Reserved = 0;
2361 Blt++;
2362 VbeBuffer += VbePixelWidth;
2363 }
2364
2365 }
2366 break;
2367
2368 case EfiBltVideoToVideo:
2369 for (Index = 0; Index < Height; Index++) {
2370 if (DestinationY <= SourceY) {
2371 SrcY = SourceY + Index;
2372 DstY = DestinationY + Index;
2373 } else {
2374 SrcY = SourceY + Height - Index - 1;
2375 DstY = DestinationY + Height - Index - 1;
2376 }
2377
2378 VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
2379 VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
2380
2381 gBS->CopyMem (
2382 VbeBuffer,
2383 VbeBuffer1,
2384 TotalBytes
2385 );
2386
2387 //
2388 // Update physical frame buffer.
2389 //
2390 CopyVideoBuffer (
2391 PciIo,
2392 VbeBuffer,
2393 MemAddress,
2394 DestinationX,
2395 DstY,
2396 TotalBytes,
2397 VbePixelWidth,
2398 BytesPerScanLine
2399 );
2400 }
2401 break;
2402
2403 case EfiBltVideoFill:
2404 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2405 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
2406 //
2407 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2408 //
2409 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2410 (
2411 (Blt->Green & Mode->Green.Mask) <<
2412 Mode->Green.Position
2413 ) |
2414 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2415
2416 for (Index = 0; Index < Width; Index++) {
2417 gBS->CopyMem (
2418 VbeBuffer,
2419 &Pixel,
2420 VbePixelWidth
2421 );
2422 VbeBuffer += VbePixelWidth;
2423 }
2424
2425 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2426 for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
2427 gBS->CopyMem (
2428 (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
2429 VbeBuffer,
2430 TotalBytes
2431 );
2432 }
2433
2434 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
2435 //
2436 // Update physical frame buffer.
2437 //
2438 CopyVideoBuffer (
2439 PciIo,
2440 VbeBuffer,
2441 MemAddress,
2442 DestinationX,
2443 DstY,
2444 TotalBytes,
2445 VbePixelWidth,
2446 BytesPerScanLine
2447 );
2448 }
2449 break;
2450
2451 case EfiBltBufferToVideo:
2452 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
2453 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2454 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2455 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2456 //
2457 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2458 //
2459 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2460 ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
2461 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2462 gBS->CopyMem (
2463 VbeBuffer,
2464 &Pixel,
2465 VbePixelWidth
2466 );
2467 Blt++;
2468 VbeBuffer += VbePixelWidth;
2469 }
2470
2471 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2472
2473 //
2474 // Update physical frame buffer.
2475 //
2476 CopyVideoBuffer (
2477 PciIo,
2478 VbeBuffer,
2479 MemAddress,
2480 DestinationX,
2481 DstY,
2482 TotalBytes,
2483 VbePixelWidth,
2484 BytesPerScanLine
2485 );
2486 }
2487 break;
2488
2489 default: ;
2490 }
2491
2492 gBS->RestoreTPL (OriginalTPL);
2493
2494 return EFI_SUCCESS;
2495 }
2496
2497 /**
2498 Graphics Output protocol instance to block transfer for VBE device.
2499
2500 @param This Pointer to Graphics Output protocol instance
2501 @param BltBuffer The data to transfer to screen
2502 @param BltOperation The operation to perform
2503 @param SourceX The X coordinate of the source for BltOperation
2504 @param SourceY The Y coordinate of the source for BltOperation
2505 @param DestinationX The X coordinate of the destination for
2506 BltOperation
2507 @param DestinationY The Y coordinate of the destination for
2508 BltOperation
2509 @param Width The width of a rectangle in the blt rectangle in
2510 pixels
2511 @param Height The height of a rectangle in the blt rectangle in
2512 pixels
2513 @param Delta Not used for EfiBltVideoFill and
2514 EfiBltVideoToVideo operation. If a Delta of 0 is
2515 used, the entire BltBuffer will be operated on. If
2516 a subrectangle of the BltBuffer is used, then
2517 Delta represents the number of bytes in a row of
2518 the BltBuffer.
2519
2520 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2521 @retval EFI_SUCCESS Blt operation success
2522
2523 **/
2524 EFI_STATUS
2525 EFIAPI
2526 BiosVideoGraphicsOutputVbeBlt (
2527 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
2528 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2529 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2530 IN UINTN SourceX,
2531 IN UINTN SourceY,
2532 IN UINTN DestinationX,
2533 IN UINTN DestinationY,
2534 IN UINTN Width,
2535 IN UINTN Height,
2536 IN UINTN Delta
2537 )
2538 {
2539 BIOS_VIDEO_DEV *BiosVideoPrivate;
2540 BIOS_VIDEO_MODE_DATA *Mode;
2541
2542 if (This == NULL) {
2543 return EFI_INVALID_PARAMETER;
2544 }
2545
2546 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2547 Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode];
2548
2549 return BiosVideoVbeBltWorker (
2550 BiosVideoPrivate,
2551 BltBuffer,
2552 BltOperation,
2553 SourceX,
2554 SourceY,
2555 DestinationX,
2556 DestinationY,
2557 Width,
2558 Height,
2559 Delta,
2560 Mode
2561 );
2562 }
2563
2564 /**
2565 Write graphics controller registers.
2566
2567 @param PciIo Pointer to PciIo protocol instance of the
2568 controller
2569 @param Address Register address
2570 @param Data Data to be written to register
2571
2572 @return None
2573
2574 **/
2575 VOID
2576 WriteGraphicsController (
2577 IN EFI_PCI_IO_PROTOCOL *PciIo,
2578 IN UINTN Address,
2579 IN UINTN Data
2580 )
2581 {
2582 Address = Address | (Data << 8);
2583 PciIo->Io.Write (
2584 PciIo,
2585 EfiPciIoWidthUint16,
2586 EFI_PCI_IO_PASS_THROUGH_BAR,
2587 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
2588 1,
2589 &Address
2590 );
2591 }
2592
2593
2594 /**
2595 Read the four bit plane of VGA frame buffer.
2596
2597 @param PciIo Pointer to PciIo protocol instance of the
2598 controller
2599 @param HardwareBuffer Hardware VGA frame buffer address
2600 @param MemoryBuffer Memory buffer address
2601 @param WidthInBytes Number of bytes in a line to read
2602 @param Height Height of the area to read
2603
2604 @return None
2605
2606 **/
2607 VOID
2608 VgaReadBitPlanes (
2609 EFI_PCI_IO_PROTOCOL *PciIo,
2610 UINT8 *HardwareBuffer,
2611 UINT8 *MemoryBuffer,
2612 UINTN WidthInBytes,
2613 UINTN Height
2614 )
2615 {
2616 UINTN BitPlane;
2617 UINTN Rows;
2618 UINTN FrameBufferOffset;
2619 UINT8 *Source;
2620 UINT8 *Destination;
2621
2622 //
2623 // Program the Mode Register Write mode 0, Read mode 0
2624 //
2625 WriteGraphicsController (
2626 PciIo,
2627 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2628 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2629 );
2630
2631 for (BitPlane = 0, FrameBufferOffset = 0;
2632 BitPlane < VGA_NUMBER_OF_BIT_PLANES;
2633 BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
2634 ) {
2635 //
2636 // Program the Read Map Select Register to select the correct bit plane
2637 //
2638 WriteGraphicsController (
2639 PciIo,
2640 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
2641 BitPlane
2642 );
2643
2644 Source = HardwareBuffer;
2645 Destination = MemoryBuffer + FrameBufferOffset;
2646
2647 for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
2648 PciIo->Mem.Read (
2649 PciIo,
2650 EfiPciIoWidthUint8,
2651 EFI_PCI_IO_PASS_THROUGH_BAR,
2652 (UINT64) (UINTN) Source,
2653 WidthInBytes,
2654 (VOID *) Destination
2655 );
2656 }
2657 }
2658 }
2659
2660
2661 /**
2662 Internal routine to convert VGA color to Grahpics Output color.
2663
2664 @param MemoryBuffer Buffer containing VGA color
2665 @param CoordinateX The X coordinate of pixel on screen
2666 @param CoordinateY The Y coordinate of pixel on screen
2667 @param BltBuffer Buffer to contain converted Grahpics Output color
2668
2669 @return None
2670
2671 **/
2672 VOID
2673 VgaConvertToGraphicsOutputColor (
2674 UINT8 *MemoryBuffer,
2675 UINTN CoordinateX,
2676 UINTN CoordinateY,
2677 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2678 )
2679 {
2680 UINTN Mask;
2681 UINTN Bit;
2682 UINTN Color;
2683
2684 MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
2685 Mask = mVgaBitMaskTable[CoordinateX & 0x07];
2686 for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
2687 if ((*MemoryBuffer & Mask) != 0) {
2688 Color |= Bit;
2689 }
2690 }
2691
2692 *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
2693 }
2694
2695 /**
2696 Internal routine to convert Grahpics Output color to VGA color.
2697
2698 @param BltBuffer buffer containing Grahpics Output color
2699
2700 @return Converted VGA color
2701
2702 **/
2703 UINT8
2704 VgaConvertColor (
2705 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2706 )
2707 {
2708 UINT8 Color;
2709
2710 Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
2711 if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
2712 Color |= 0x08;
2713 }
2714
2715 return Color;
2716 }
2717
2718
2719 /**
2720 Grahpics Output protocol instance to block transfer for VGA device.
2721
2722 @param This Pointer to Grahpics Output protocol instance
2723 @param BltBuffer The data to transfer to screen
2724 @param BltOperation The operation to perform
2725 @param SourceX The X coordinate of the source for BltOperation
2726 @param SourceY The Y coordinate of the source for BltOperation
2727 @param DestinationX The X coordinate of the destination for
2728 BltOperation
2729 @param DestinationY The Y coordinate of the destination for
2730 BltOperation
2731 @param Width The width of a rectangle in the blt rectangle in
2732 pixels
2733 @param Height The height of a rectangle in the blt rectangle in
2734 pixels
2735 @param Delta Not used for EfiBltVideoFill and
2736 EfiBltVideoToVideo operation. If a Delta of 0 is
2737 used, the entire BltBuffer will be operated on. If
2738 a subrectangle of the BltBuffer is used, then
2739 Delta represents the number of bytes in a row of
2740 the BltBuffer.
2741
2742 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2743 @retval EFI_SUCCESS Blt operation success
2744
2745 **/
2746 EFI_STATUS
2747 EFIAPI
2748 BiosVideoGraphicsOutputVgaBlt (
2749 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
2750 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2751 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2752 IN UINTN SourceX,
2753 IN UINTN SourceY,
2754 IN UINTN DestinationX,
2755 IN UINTN DestinationY,
2756 IN UINTN Width,
2757 IN UINTN Height,
2758 IN UINTN Delta
2759 )
2760 {
2761 BIOS_VIDEO_DEV *BiosVideoPrivate;
2762 EFI_TPL OriginalTPL;
2763 UINT8 *MemAddress;
2764 UINTN BytesPerScanLine;
2765 UINTN Bit;
2766 UINTN Index;
2767 UINTN Index1;
2768 UINTN StartAddress;
2769 UINTN Bytes;
2770 UINTN Offset;
2771 UINT8 LeftMask;
2772 UINT8 RightMask;
2773 UINTN Address;
2774 UINTN AddressFix;
2775 UINT8 *Address1;
2776 UINT8 *SourceAddress;
2777 UINT8 *DestinationAddress;
2778 EFI_PCI_IO_PROTOCOL *PciIo;
2779 UINT8 Data;
2780 UINT8 PixelColor;
2781 UINT8 *VgaFrameBuffer;
2782 UINTN SourceOffset;
2783 UINTN SourceWidth;
2784 UINTN Rows;
2785 UINTN Columns;
2786 UINTN CoordinateX;
2787 UINTN CoordinateY;
2788 UINTN CurrentMode;
2789
2790 if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2791 return EFI_INVALID_PARAMETER;
2792 }
2793
2794 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2795
2796 CurrentMode = This->Mode->Mode;
2797 PciIo = BiosVideoPrivate->PciIo;
2798 MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
2799 BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
2800 VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
2801
2802
2803 if (Width == 0 || Height == 0) {
2804 return EFI_INVALID_PARAMETER;
2805 }
2806 //
2807 // We need to fill the Virtual Screen buffer with the blt data.
2808 // The virtual screen is upside down, as the first row is the bootom row of
2809 // the image.
2810 //
2811 if (BltOperation == EfiBltVideoToBltBuffer) {
2812 //
2813 // Video to BltBuffer: Source is Video, destination is BltBuffer
2814 //
2815 if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2816 return EFI_INVALID_PARAMETER;
2817 }
2818
2819 if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2820 return EFI_INVALID_PARAMETER;
2821 }
2822 } else {
2823 //
2824 // BltBuffer to Video: Source is BltBuffer, destination is Video
2825 //
2826 if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2827 return EFI_INVALID_PARAMETER;
2828 }
2829
2830 if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2831 return EFI_INVALID_PARAMETER;
2832 }
2833 }
2834 //
2835 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2836 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2837 // the number of bytes in each row can be computed.
2838 //
2839 if (Delta == 0) {
2840 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2841 }
2842 //
2843 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2844 // We would not want a timer based event (Cursor, ...) to come in while we are
2845 // doing this operation.
2846 //
2847 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2848
2849 //
2850 // Compute some values we need for VGA
2851 //
2852 switch (BltOperation) {
2853 case EfiBltVideoToBltBuffer:
2854
2855 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2856 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2857
2858 //
2859 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2860 //
2861 VgaReadBitPlanes (
2862 PciIo,
2863 MemAddress + SourceOffset,
2864 VgaFrameBuffer + SourceOffset,
2865 SourceWidth,
2866 Height
2867 );
2868
2869 //
2870 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2871 //
2872 BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2873 for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
2874 for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
2875 VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
2876 }
2877
2878 BltBuffer -= Width;
2879 }
2880
2881 break;
2882
2883 case EfiBltVideoToVideo:
2884 //
2885 // Check for an aligned Video to Video operation
2886 //
2887 if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2888 //
2889 // Program the Mode Register Write mode 1, Read mode 0
2890 //
2891 WriteGraphicsController (
2892 PciIo,
2893 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2894 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2895 );
2896
2897 SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2898 DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2899 Bytes = Width >> 3;
2900 for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2901 PciIo->CopyMem (
2902 PciIo,
2903 EfiPciIoWidthUint8,
2904 EFI_PCI_IO_PASS_THROUGH_BAR,
2905 (UINT64) (UINTN) (DestinationAddress + Offset),
2906 EFI_PCI_IO_PASS_THROUGH_BAR,
2907 (UINT64) (UINTN) (SourceAddress + Offset),
2908 Bytes
2909 );
2910 }
2911 } else {
2912 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2913 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2914
2915 //
2916 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2917 //
2918 VgaReadBitPlanes (
2919 PciIo,
2920 MemAddress + SourceOffset,
2921 VgaFrameBuffer + SourceOffset,
2922 SourceWidth,
2923 Height
2924 );
2925 }
2926
2927 break;
2928
2929 case EfiBltVideoFill:
2930 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2931 Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2932 LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
2933 RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2934 if (Bytes == 0) {
2935 LeftMask = (UINT8) (LeftMask & RightMask);
2936 RightMask = 0;
2937 }
2938
2939 if (LeftMask == 0xff) {
2940 StartAddress--;
2941 Bytes++;
2942 LeftMask = 0;
2943 }
2944
2945 if (RightMask == 0xff) {
2946 Bytes++;
2947 RightMask = 0;
2948 }
2949
2950 PixelColor = VgaConvertColor (BltBuffer);
2951
2952 //
2953 // Program the Mode Register Write mode 2, Read mode 0
2954 //
2955 WriteGraphicsController (
2956 PciIo,
2957 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2958 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2959 );
2960
2961 //
2962 // Program the Data Rotate/Function Select Register to replace
2963 //
2964 WriteGraphicsController (
2965 PciIo,
2966 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2967 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2968 );
2969
2970 if (LeftMask != 0) {
2971 //
2972 // Program the BitMask register with the Left column mask
2973 //
2974 WriteGraphicsController (
2975 PciIo,
2976 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2977 LeftMask
2978 );
2979
2980 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2981 //
2982 // Read data from the bit planes into the latches
2983 //
2984 PciIo->Mem.Read (
2985 PciIo,
2986 EfiPciIoWidthUint8,
2987 EFI_PCI_IO_PASS_THROUGH_BAR,
2988 (UINT64) (UINTN) Address,
2989 1,
2990 &Data
2991 );
2992 //
2993 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2994 //
2995 PciIo->Mem.Write (
2996 PciIo,
2997 EfiPciIoWidthUint8,
2998 EFI_PCI_IO_PASS_THROUGH_BAR,
2999 (UINT64) (UINTN) Address,
3000 1,
3001 &PixelColor
3002 );
3003 }
3004 }
3005
3006 if (Bytes > 1) {
3007 //
3008 // Program the BitMask register with the middle column mask of 0xff
3009 //
3010 WriteGraphicsController (
3011 PciIo,
3012 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3013 0xff
3014 );
3015
3016 for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
3017 PciIo->Mem.Write (
3018 PciIo,
3019 EfiPciIoWidthFillUint8,
3020 EFI_PCI_IO_PASS_THROUGH_BAR,
3021 (UINT64) (UINTN) Address,
3022 Bytes - 1,
3023 &PixelColor
3024 );
3025 }
3026 }
3027
3028 if (RightMask != 0) {
3029 //
3030 // Program the BitMask register with the Right column mask
3031 //
3032 WriteGraphicsController (
3033 PciIo,
3034 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3035 RightMask
3036 );
3037
3038 for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
3039 //
3040 // Read data from the bit planes into the latches
3041 //
3042 PciIo->Mem.Read (
3043 PciIo,
3044 EfiPciIoWidthUint8,
3045 EFI_PCI_IO_PASS_THROUGH_BAR,
3046 (UINT64) (UINTN) Address,
3047 1,
3048 &Data
3049 );
3050 //
3051 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3052 //
3053 PciIo->Mem.Write (
3054 PciIo,
3055 EfiPciIoWidthUint8,
3056 EFI_PCI_IO_PASS_THROUGH_BAR,
3057 (UINT64) (UINTN) Address,
3058 1,
3059 &PixelColor
3060 );
3061 }
3062 }
3063 break;
3064
3065 case EfiBltBufferToVideo:
3066 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
3067 LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
3068
3069 //
3070 // Program the Mode Register Write mode 2, Read mode 0
3071 //
3072 WriteGraphicsController (
3073 PciIo,
3074 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
3075 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3076 );
3077
3078 //
3079 // Program the Data Rotate/Function Select Register to replace
3080 //
3081 WriteGraphicsController (
3082 PciIo,
3083 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
3084 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3085 );
3086
3087 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
3088 for (Index1 = 0; Index1 < Width; Index1++) {
3089 BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
3090 }
3091 AddressFix = Address;
3092
3093 for (Bit = 0; Bit < 8; Bit++) {
3094 //
3095 // Program the BitMask register with the Left column mask
3096 //
3097 WriteGraphicsController (
3098 PciIo,
3099 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3100 LeftMask
3101 );
3102
3103 for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
3104 //
3105 // Read data from the bit planes into the latches
3106 //
3107 PciIo->Mem.Read (
3108 PciIo,
3109 EfiPciIoWidthUint8,
3110 EFI_PCI_IO_PASS_THROUGH_BAR,
3111 (UINT64) (UINTN) Address1,
3112 1,
3113 &Data
3114 );
3115
3116 PciIo->Mem.Write (
3117 PciIo,
3118 EfiPciIoWidthUint8,
3119 EFI_PCI_IO_PASS_THROUGH_BAR,
3120 (UINT64) (UINTN) Address1,
3121 1,
3122 &BiosVideoPrivate->LineBuffer[Index1]
3123 );
3124 }
3125
3126 LeftMask = (UINT8) (LeftMask >> 1);
3127 if (LeftMask == 0) {
3128 LeftMask = 0x80;
3129 AddressFix++;
3130 }
3131 }
3132 }
3133
3134 break;
3135
3136 default: ;
3137 }
3138
3139 gBS->RestoreTPL (OriginalTPL);
3140
3141 return EFI_SUCCESS;
3142 }
3143
3144 //
3145 // VGA Mini Port Protocol Functions
3146 //
3147
3148 /**
3149 VgaMiniPort protocol interface to set mode.
3150
3151 @param This Pointer to VgaMiniPort protocol instance
3152 @param ModeNumber The index of the mode
3153
3154 @retval EFI_UNSUPPORTED The requested mode is not supported
3155 @retval EFI_SUCCESS The requested mode is set successfully
3156
3157 **/
3158 EFI_STATUS
3159 EFIAPI
3160 BiosVideoVgaMiniPortSetMode (
3161 IN EFI_VGA_MINI_PORT_PROTOCOL *This,
3162 IN UINTN ModeNumber
3163 )
3164 {
3165 BIOS_VIDEO_DEV *BiosVideoPrivate;
3166 EFI_IA32_REGISTER_SET Regs;
3167
3168 if (This == NULL) {
3169 return EFI_INVALID_PARAMETER;
3170 }
3171
3172 //
3173 // Make sure the ModeNumber is a valid value
3174 //
3175 if (ModeNumber >= This->MaxMode) {
3176 return EFI_UNSUPPORTED;
3177 }
3178 //
3179 // Get the device structure for this device
3180 //
3181 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
3182
3183 switch (ModeNumber) {
3184 case 0:
3185 //
3186 // Set the 80x25 Text VGA Mode
3187 //
3188 Regs.H.AH = 0x00;
3189 Regs.H.AL = 0x83;
3190 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3191
3192 Regs.H.AH = 0x11;
3193 Regs.H.AL = 0x14;
3194 Regs.H.BL = 0;
3195 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3196 break;
3197
3198 case 1:
3199 //
3200 // Set the 80x50 Text VGA Mode
3201 //
3202 Regs.H.AH = 0x00;
3203 Regs.H.AL = 0x83;
3204 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3205 Regs.H.AH = 0x11;
3206 Regs.H.AL = 0x12;
3207 Regs.H.BL = 0;
3208 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3209 break;
3210
3211 default:
3212 return EFI_UNSUPPORTED;
3213 }
3214
3215 return EFI_SUCCESS;
3216 }
3217
3218 /**
3219 Event handler for Exit Boot Service.
3220
3221 @param Event The event that be siganlled when exiting boot service.
3222 @param Context Pointer to instance of BIOS_VIDEO_DEV.
3223
3224 **/
3225 VOID
3226 EFIAPI
3227 BiosVideoNotifyExitBootServices (
3228 IN EFI_EVENT Event,
3229 IN VOID *Context
3230 )
3231 {
3232 BIOS_VIDEO_DEV *BiosVideoPrivate;
3233 EFI_IA32_REGISTER_SET Regs;
3234
3235 BiosVideoPrivate = (BIOS_VIDEO_DEV *)Context;
3236
3237 //
3238 // Set the 80x25 Text VGA Mode
3239 //
3240 Regs.H.AH = 0x00;
3241 Regs.H.AL = 0x03;
3242 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3243
3244 Regs.H.AH = 0x00;
3245 Regs.H.AL = 0x83;
3246 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3247
3248 Regs.H.AH = 0x11;
3249 Regs.H.AL = 0x04;
3250 Regs.H.BL = 0;
3251 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3252 }
3253
3254 /**
3255 The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3256
3257 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3258 @param[in] SystemTable A pointer to the EFI System Table.
3259
3260 @retval EFI_SUCCESS The entry point is executed successfully.
3261 @retval other Some error occurs when executing this entry point.
3262
3263 **/
3264 EFI_STATUS
3265 EFIAPI
3266 BiosVideoEntryPoint(
3267 IN EFI_HANDLE ImageHandle,
3268 IN EFI_SYSTEM_TABLE *SystemTable
3269 )
3270 {
3271 EFI_STATUS Status;
3272
3273 //
3274 // Install driver model protocol(s).
3275 //
3276 Status = EfiLibInstallDriverBindingComponentName2 (
3277 ImageHandle,
3278 SystemTable,
3279 &gBiosVideoDriverBinding,
3280 ImageHandle,
3281 &gBiosVideoComponentName,
3282 &gBiosVideoComponentName2
3283 );
3284 ASSERT_EFI_ERROR (Status);
3285
3286 //
3287 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3288 //
3289 return gBS->InstallMultipleProtocolInterfaces (
3290 &ImageHandle,
3291 &gEfiLegacyBiosGuid,
3292 NULL,
3293 NULL
3294 );
3295 }
3296