]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
7c718ba423d750031989c6f659c98c39d6cb9f80
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / VideoDxe / BiosVideo.c
1 /** @file
2 ConsoleOut Routines that speak VGA.
3
4 Copyright (c) 2007 - 2013, 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 &= (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 EFI_STATUS Status;
1261
1262 EntryCount = 0;
1263 HasChild = FALSE;
1264 Status = gBS->OpenProtocolInformation (
1265 Controller,
1266 &gEfiPciIoProtocolGuid,
1267 &OpenInfoBuffer,
1268 &EntryCount
1269 );
1270 for (Index = 0; Index < EntryCount; Index++) {
1271 if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1272 HasChild = TRUE;
1273 }
1274 }
1275
1276 return HasChild;
1277 }
1278
1279 /**
1280 Check for VBE device.
1281
1282 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1283
1284 @retval EFI_SUCCESS VBE device found
1285
1286 **/
1287 EFI_STATUS
1288 BiosVideoCheckForVbe (
1289 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1290 )
1291 {
1292 EFI_STATUS Status;
1293 EFI_IA32_REGISTER_SET Regs;
1294 UINT16 *ModeNumberPtr;
1295 UINT16 VbeModeNumber;
1296 BOOLEAN ModeFound;
1297 BOOLEAN EdidFound;
1298 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1299 BIOS_VIDEO_MODE_DATA *CurrentModeData;
1300 UINTN PreferMode;
1301 UINTN ModeNumber;
1302 VESA_BIOS_EXTENSIONS_EDID_TIMING Timing;
1303 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
1304 EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
1305 UINT32 EdidAttributes;
1306 BOOLEAN EdidOverrideFound;
1307 UINTN EdidOverrideDataSize;
1308 UINT8 *EdidOverrideDataBlock;
1309 UINTN EdidActiveDataSize;
1310 UINT8 *EdidActiveDataBlock;
1311 UINT32 HighestHorizontalResolution;
1312 UINT32 HighestVerticalResolution;
1313 UINTN HighestResolutionMode;
1314
1315 EdidFound = TRUE;
1316 EdidOverrideFound = FALSE;
1317 EdidOverrideDataBlock = NULL;
1318 EdidActiveDataSize = 0;
1319 EdidActiveDataBlock = NULL;
1320 HighestHorizontalResolution = 0;
1321 HighestVerticalResolution = 0;
1322 HighestResolutionMode = 0;
1323
1324 //
1325 // Allocate buffer under 1MB for VBE data structures
1326 //
1327 BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
1328 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
1329 sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
1330 sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
1331 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
1332 );
1333
1334 BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
1335
1336 Status = gBS->AllocatePages (
1337 AllocateMaxAddress,
1338 EfiBootServicesData,
1339 BiosVideoPrivate->NumberOfPagesBelow1MB,
1340 &BiosVideoPrivate->PagesBelow1MB
1341 );
1342 if (EFI_ERROR (Status)) {
1343 return Status;
1344 }
1345
1346 ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
1347
1348 //
1349 // Fill in the VBE related data structures
1350 //
1351 BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
1352 BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
1353 BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
1354 BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
1355 BiosVideoPrivate->VbeSaveRestorePages = 0;
1356 BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
1357
1358 //
1359 // Test to see if the Video Adapter is compliant with VBE 3.0
1360 //
1361 gBS->SetMem (&Regs, sizeof (Regs), 0);
1362 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
1363 gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
1364 BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
1365 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1366 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1367
1368 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1369
1370 Status = EFI_DEVICE_ERROR;
1371
1372 //
1373 // See if the VESA call succeeded
1374 //
1375 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1376 return Status;
1377 }
1378 //
1379 // Check for 'VESA' signature
1380 //
1381 if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
1382 return Status;
1383 }
1384 //
1385 // Check to see if this is VBE 2.0 or higher
1386 //
1387 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
1388 return Status;
1389 }
1390
1391 EdidFound = FALSE;
1392 EdidAttributes = 0xff;
1393 EdidOverrideDataSize = 0;
1394
1395 //
1396 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1397 //
1398 Status = gBS->LocateProtocol (
1399 &gEfiEdidOverrideProtocolGuid,
1400 NULL,
1401 (VOID **) &EdidOverride
1402 );
1403 if (!EFI_ERROR (Status)) {
1404 //
1405 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1406 //
1407 EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);
1408 if (NULL == EdidOverrideDataBlock) {
1409 Status = EFI_OUT_OF_RESOURCES;
1410 goto Done;
1411 }
1412
1413 Status = EdidOverride->GetEdid (
1414 EdidOverride,
1415 BiosVideoPrivate->Handle,
1416 &EdidAttributes,
1417 &EdidOverrideDataSize,
1418 (UINT8 **) &EdidOverrideDataBlock
1419 );
1420 if (!EFI_ERROR (Status) &&
1421 EdidAttributes == 0 &&
1422 EdidOverrideDataSize != 0) {
1423 //
1424 // Succeeded to get EDID Override Data
1425 //
1426 EdidOverrideFound = TRUE;
1427 }
1428 }
1429
1430 if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
1431 //
1432 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1433 // read EDID information through INT10 call
1434 //
1435
1436 gBS->SetMem (&Regs, sizeof (Regs), 0);
1437 Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
1438 Regs.X.BX = 1;
1439 Regs.X.CX = 0;
1440 Regs.X.DX = 0;
1441 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1442 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1443
1444 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1445 //
1446 // See if the VESA call succeeded
1447 //
1448 if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1449 //
1450 // Set EDID Discovered Data
1451 //
1452 BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1453 BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
1454 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1455 BiosVideoPrivate->VbeEdidDataBlock
1456 );
1457
1458 if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
1459 Status = EFI_OUT_OF_RESOURCES;
1460 goto Done;
1461 }
1462
1463 EdidFound = TRUE;
1464 }
1465 }
1466
1467 if (EdidFound) {
1468 EdidActiveDataSize = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1469 EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
1470 } else if (EdidOverrideFound) {
1471 EdidActiveDataSize = EdidOverrideDataSize;
1472 EdidActiveDataBlock = EdidOverrideDataBlock;
1473 EdidFound = TRUE;
1474 }
1475
1476 if (EdidFound) {
1477 //
1478 // Parse EDID data structure to retrieve modes supported by monitor
1479 //
1480 if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
1481 //
1482 // Copy EDID Override Data to EDID Active Data
1483 //
1484 BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
1485 BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
1486 EdidActiveDataSize,
1487 EdidActiveDataBlock
1488 );
1489 if (NULL == BiosVideoPrivate->EdidActive.Edid) {
1490 Status = EFI_OUT_OF_RESOURCES;
1491 goto Done;
1492 }
1493 }
1494 } else {
1495 BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
1496 BiosVideoPrivate->EdidActive.Edid = NULL;
1497 EdidFound = FALSE;
1498 }
1499
1500 //
1501 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1502 //
1503 ModeNumberPtr = (UINT16 *)
1504 (
1505 (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
1506 ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
1507 );
1508
1509 PreferMode = 0;
1510 ModeNumber = 0;
1511
1512 //
1513 // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1514 //
1515 for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);
1516 VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;
1517 VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {
1518 //
1519 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1520 //
1521 if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
1522 continue;
1523 }
1524 //
1525 // Get the information about the mode
1526 //
1527 gBS->SetMem (&Regs, sizeof (Regs), 0);
1528 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
1529 Regs.X.CX = VbeModeNumber;
1530 gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
1531 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1532 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1533
1534 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1535
1536 //
1537 // See if the call succeeded. If it didn't, then try the next mode.
1538 //
1539 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1540 continue;
1541 }
1542 //
1543 // See if the mode supports color. If it doesn't then try the next mode.
1544 //
1545 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
1546 continue;
1547 }
1548 //
1549 // See if the mode supports graphics. If it doesn't then try the next mode.
1550 //
1551 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
1552 continue;
1553 }
1554 //
1555 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1556 //
1557 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
1558 continue;
1559 }
1560 //
1561 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1562 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1563 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1564 //
1565 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
1566 continue;
1567 }
1568
1569 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
1570 continue;
1571 }
1572
1573 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
1574 continue;
1575 }
1576 //
1577 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1578 //
1579 if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
1580 continue;
1581 }
1582
1583 DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",
1584 VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));
1585
1586 if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
1587 //
1588 // EDID exist, check whether this mode match with any mode in EDID
1589 //
1590 Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1591 Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1592 if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
1593 //
1594 // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1595 // but INT10 can support these modes, we add them into GOP mode.
1596 //
1597 if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&
1598 !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&
1599 !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&
1600 !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {
1601 continue;
1602 }
1603 }
1604 }
1605
1606 //
1607 // Select a reasonable mode to be set for current display mode
1608 //
1609 ModeFound = FALSE;
1610
1611 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
1612 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
1613 ) {
1614 ModeFound = TRUE;
1615 }
1616 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
1617 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
1618 ) {
1619 ModeFound = TRUE;
1620 PreferMode = ModeNumber;
1621 }
1622 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
1623 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
1624 ) {
1625 ModeFound = TRUE;
1626 }
1627
1628 if ((!EdidFound) && (!ModeFound)) {
1629 //
1630 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1631 //
1632 continue;
1633 }
1634
1635 //
1636 // Record the highest resolution mode to set later
1637 //
1638 if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||
1639 ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&
1640 (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {
1641 HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1642 HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1643 HighestResolutionMode = ModeNumber;
1644 }
1645
1646 //
1647 // Add mode to the list of available modes
1648 //
1649 ModeNumber ++;
1650 ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1651 ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
1652 );
1653 if (NULL == ModeBuffer) {
1654 Status = EFI_OUT_OF_RESOURCES;
1655 goto Done;
1656 }
1657
1658 if (ModeNumber > 1) {
1659 CopyMem (
1660 ModeBuffer,
1661 BiosVideoPrivate->ModeData,
1662 (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1663 );
1664 }
1665
1666 if (BiosVideoPrivate->ModeData != NULL) {
1667 FreePool (BiosVideoPrivate->ModeData);
1668 }
1669
1670 CurrentModeData = &ModeBuffer[ModeNumber - 1];
1671 CurrentModeData->VbeModeNumber = VbeModeNumber;
1672 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
1673 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
1674 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
1675 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
1676 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
1677 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
1678 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
1679 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
1680 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
1681 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
1682 } else {
1683 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1684 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1685 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1686 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1687 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1688 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1689 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1690 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
1691 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
1692 }
1693
1694 CurrentModeData->PixelFormat = PixelBitMask;
1695 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
1696 (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
1697 if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
1698 CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
1699 } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
1700 CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
1701 }
1702 }
1703
1704 CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
1705 CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
1706 CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
1707 CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
1708
1709 CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1710 CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1711 CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1712
1713 CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1714 CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
1715 //
1716 // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1717 //
1718 ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));
1719
1720 BiosVideoPrivate->ModeData = ModeBuffer;
1721 }
1722 //
1723 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1724 //
1725 if (ModeNumber == 0) {
1726 Status = EFI_DEVICE_ERROR;
1727 goto Done;
1728 }
1729
1730 //
1731 // Assign Gop's Blt function
1732 //
1733 BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt;
1734
1735 BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
1736 //
1737 // Current mode is unknow till now, set it to an invalid mode.
1738 //
1739 BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1740
1741 //
1742 // Find the best mode to initialize
1743 //
1744 if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {
1745 DEBUG_CODE (
1746 BIOS_VIDEO_MODE_DATA *ModeData;
1747 ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];
1748 DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",
1749 ModeData->HorizontalResolution, ModeData->VerticalResolution));
1750 );
1751 PreferMode = HighestResolutionMode;
1752 }
1753 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
1754 if (EFI_ERROR (Status)) {
1755 for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
1756 Status = BiosVideoGraphicsOutputSetMode (
1757 &BiosVideoPrivate->GraphicsOutput,
1758 (UINT32) PreferMode
1759 );
1760 if (!EFI_ERROR (Status)) {
1761 break;
1762 }
1763 }
1764 if (PreferMode == ModeNumber) {
1765 //
1766 // None mode is set successfully.
1767 //
1768 goto Done;
1769 }
1770 }
1771
1772 Done:
1773 //
1774 // If there was an error, then free the mode structure
1775 //
1776 if (EFI_ERROR (Status)) {
1777 if (BiosVideoPrivate->ModeData != NULL) {
1778 FreePool (BiosVideoPrivate->ModeData);
1779 BiosVideoPrivate->ModeData = NULL;
1780 BiosVideoPrivate->MaxMode = 0;
1781 }
1782 if (EdidOverrideDataBlock != NULL) {
1783 FreePool (EdidOverrideDataBlock);
1784 }
1785 }
1786
1787 return Status;
1788 }
1789
1790
1791 /**
1792 Check for VGA device.
1793
1794 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1795
1796 @retval EFI_SUCCESS Standard VGA device found
1797
1798 **/
1799 EFI_STATUS
1800 BiosVideoCheckForVga (
1801 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1802 )
1803 {
1804 EFI_STATUS Status;
1805 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1806
1807 Status = EFI_UNSUPPORTED;
1808
1809 //
1810 // Assign Gop's Blt function
1811 //
1812 BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt;
1813
1814 //
1815 // Add mode to the list of available modes
1816 // caller should guarantee that Mode has been allocated.
1817 //
1818 ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
1819 BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
1820
1821 ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
1822 sizeof (BIOS_VIDEO_MODE_DATA)
1823 );
1824 if (NULL == ModeBuffer) {
1825 Status = EFI_OUT_OF_RESOURCES;
1826 goto Done;
1827 }
1828
1829 ModeBuffer->VbeModeNumber = 0x0012;
1830 ModeBuffer->BytesPerScanLine = 640;
1831 ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000);
1832 ModeBuffer->HorizontalResolution = 640;
1833 ModeBuffer->VerticalResolution = 480;
1834 ModeBuffer->PixelFormat = PixelBltOnly;
1835 ModeBuffer->BitsPerPixel = 8;
1836 ModeBuffer->ColorDepth = 32;
1837 ModeBuffer->RefreshRate = 60;
1838
1839 BiosVideoPrivate->ModeData = ModeBuffer;
1840
1841 //
1842 // Test to see if the Video Adapter support the 640x480 16 color mode
1843 //
1844 BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1845 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
1846
1847 Done:
1848 //
1849 // If there was an error, then free the mode structure
1850 //
1851 if (EFI_ERROR (Status)) {
1852 if (BiosVideoPrivate->ModeData != NULL) {
1853 FreePool (BiosVideoPrivate->ModeData);
1854 BiosVideoPrivate->ModeData = NULL;
1855 }
1856 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1857 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1858 FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1859 BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
1860 }
1861 FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1862 BiosVideoPrivate->GraphicsOutput.Mode = NULL;
1863 }
1864 }
1865 return Status;
1866 }
1867
1868 //
1869 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1870 //
1871
1872 /**
1873 Graphics Output protocol interface to get video mode.
1874
1875 @param This Protocol instance pointer.
1876 @param ModeNumber The mode number to return information on.
1877 @param SizeOfInfo A pointer to the size, in bytes, of the Info
1878 buffer.
1879 @param Info Caller allocated buffer that returns information
1880 about ModeNumber.
1881
1882 @retval EFI_SUCCESS Mode information returned.
1883 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
1884 video mode.
1885 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
1886 @retval EFI_INVALID_PARAMETER One of the input args was NULL.
1887
1888 **/
1889 EFI_STATUS
1890 EFIAPI
1891 BiosVideoGraphicsOutputQueryMode (
1892 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
1893 IN UINT32 ModeNumber,
1894 OUT UINTN *SizeOfInfo,
1895 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
1896 )
1897 {
1898 BIOS_VIDEO_DEV *BiosVideoPrivate;
1899 BIOS_VIDEO_MODE_DATA *ModeData;
1900
1901 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1902
1903 if (BiosVideoPrivate->HardwareNeedsStarting) {
1904 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1905 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1906 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
1907 BiosVideoPrivate->GopDevicePath
1908 );
1909 return EFI_NOT_STARTED;
1910 }
1911
1912 if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
1913 return EFI_INVALID_PARAMETER;
1914 }
1915
1916 *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
1917 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
1918 );
1919 if (NULL == *Info) {
1920 return EFI_OUT_OF_RESOURCES;
1921 }
1922
1923 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1924
1925 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1926 (*Info)->Version = 0;
1927 (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
1928 (*Info)->VerticalResolution = ModeData->VerticalResolution;
1929 (*Info)->PixelFormat = ModeData->PixelFormat;
1930 CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
1931
1932 (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1933
1934 return EFI_SUCCESS;
1935 }
1936
1937 /**
1938 Worker function to set video mode.
1939
1940 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
1941 @param ModeData The mode data to be set.
1942 @param DevicePath Pointer to Device Path Protocol.
1943
1944 @retval EFI_SUCCESS Graphics mode was changed.
1945 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1946 request.
1947 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
1948
1949 **/
1950 EFI_STATUS
1951 BiosVideoSetModeWorker (
1952 IN BIOS_VIDEO_DEV *BiosVideoPrivate,
1953 IN BIOS_VIDEO_MODE_DATA *ModeData,
1954 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1955 )
1956 {
1957 EFI_STATUS Status;
1958 EFI_IA32_REGISTER_SET Regs;
1959
1960 if (BiosVideoPrivate->LineBuffer != NULL) {
1961 FreePool (BiosVideoPrivate->LineBuffer);
1962 }
1963
1964 if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
1965 FreePool (BiosVideoPrivate->VgaFrameBuffer);
1966 }
1967
1968 if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
1969 FreePool (BiosVideoPrivate->VbeFrameBuffer);
1970 }
1971
1972 BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
1973 ModeData->BytesPerScanLine
1974 );
1975 if (NULL == BiosVideoPrivate->LineBuffer) {
1976 return EFI_OUT_OF_RESOURCES;
1977 }
1978 //
1979 // Clear all registers
1980 //
1981 ZeroMem (&Regs, sizeof (Regs));
1982
1983 if (ModeData->VbeModeNumber < 0x100) {
1984 //
1985 // Allocate a working buffer for BLT operations to the VGA frame buffer
1986 //
1987 BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
1988 if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
1989 return EFI_OUT_OF_RESOURCES;
1990 }
1991 //
1992 // Set VGA Mode
1993 //
1994 Regs.X.AX = ModeData->VbeModeNumber;
1995 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
1996
1997 } else {
1998 //
1999 // Allocate a working buffer for BLT operations to the VBE frame buffer
2000 //
2001 BiosVideoPrivate->VbeFrameBuffer =
2002 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
2003 ModeData->BytesPerScanLine * ModeData->VerticalResolution
2004 );
2005 if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
2006 return EFI_OUT_OF_RESOURCES;
2007 }
2008 //
2009 // Set VBE mode
2010 //
2011 Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
2012 Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
2013 ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
2014 Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2015 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
2016 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
2017
2018 //
2019 // Check to see if the call succeeded
2020 //
2021 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
2022 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2023 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2024 EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
2025 DevicePath
2026 );
2027 return EFI_DEVICE_ERROR;
2028 }
2029 //
2030 // Initialize the state of the VbeFrameBuffer
2031 //
2032 Status = BiosVideoPrivate->PciIo->Mem.Read (
2033 BiosVideoPrivate->PciIo,
2034 EfiPciIoWidthUint32,
2035 EFI_PCI_IO_PASS_THROUGH_BAR,
2036 (UINT64) (UINTN) ModeData->LinearFrameBuffer,
2037 (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
2038 BiosVideoPrivate->VbeFrameBuffer
2039 );
2040 if (EFI_ERROR (Status)) {
2041 return Status;
2042 }
2043 }
2044
2045 return EFI_SUCCESS;
2046 }
2047
2048 /**
2049 Graphics Output protocol interface to set video mode.
2050
2051 @param This Protocol instance pointer.
2052 @param ModeNumber The mode number to be set.
2053
2054 @retval EFI_SUCCESS Graphics mode was changed.
2055 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
2056 request.
2057 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
2058
2059 **/
2060 EFI_STATUS
2061 EFIAPI
2062 BiosVideoGraphicsOutputSetMode (
2063 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
2064 IN UINT32 ModeNumber
2065 )
2066 {
2067 EFI_STATUS Status;
2068 BIOS_VIDEO_DEV *BiosVideoPrivate;
2069 BIOS_VIDEO_MODE_DATA *ModeData;
2070 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
2071
2072 if (This == NULL) {
2073 return EFI_INVALID_PARAMETER;
2074 }
2075
2076 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2077
2078 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
2079
2080 if (ModeNumber >= This->Mode->MaxMode) {
2081 return EFI_UNSUPPORTED;
2082 }
2083
2084 if (ModeNumber == This->Mode->Mode) {
2085 //
2086 // Clear screen to black
2087 //
2088 ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2089 BiosVideoGraphicsOutputVbeBlt (
2090 This,
2091 &Background,
2092 EfiBltVideoFill,
2093 0,
2094 0,
2095 0,
2096 0,
2097 ModeData->HorizontalResolution,
2098 ModeData->VerticalResolution,
2099 0
2100 );
2101 return EFI_SUCCESS;
2102 }
2103
2104 Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
2105 if (EFI_ERROR (Status)) {
2106 return Status;
2107 }
2108
2109 This->Mode->Mode = ModeNumber;
2110 This->Mode->Info->Version = 0;
2111 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
2112 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
2113 This->Mode->Info->PixelFormat = ModeData->PixelFormat;
2114 CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
2115 This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
2116 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
2117 This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
2118 This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
2119
2120 BiosVideoPrivate->HardwareNeedsStarting = FALSE;
2121
2122 return EFI_SUCCESS;
2123 }
2124
2125 /**
2126 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2127
2128 @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
2129 @param VbeBuffer The data to transfer to screen
2130 @param MemAddress Physical frame buffer base address
2131 @param DestinationX The X coordinate of the destination for BltOperation
2132 @param DestinationY The Y coordinate of the destination for BltOperation
2133 @param TotalBytes The total bytes of copy
2134 @param VbePixelWidth Bytes per pixel
2135 @param BytesPerScanLine Bytes per scan line
2136
2137 **/
2138 VOID
2139 CopyVideoBuffer (
2140 IN EFI_PCI_IO_PROTOCOL *PciIo,
2141 IN UINT8 *VbeBuffer,
2142 IN VOID *MemAddress,
2143 IN UINTN DestinationX,
2144 IN UINTN DestinationY,
2145 IN UINTN TotalBytes,
2146 IN UINT32 VbePixelWidth,
2147 IN UINTN BytesPerScanLine
2148 )
2149 {
2150 UINTN FrameBufferAddr;
2151 UINTN CopyBlockNum;
2152 UINTN RemainingBytes;
2153 UINTN UnalignedBytes;
2154 EFI_STATUS Status;
2155
2156 FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
2157
2158 //
2159 // If TotalBytes is less than 4 bytes, only start byte copy.
2160 //
2161 if (TotalBytes < 4) {
2162 Status = PciIo->Mem.Write (
2163 PciIo,
2164 EfiPciIoWidthUint8,
2165 EFI_PCI_IO_PASS_THROUGH_BAR,
2166 (UINT64) FrameBufferAddr,
2167 TotalBytes,
2168 VbeBuffer
2169 );
2170 ASSERT_EFI_ERROR (Status);
2171 return;
2172 }
2173
2174 //
2175 // If VbeBuffer is not 4-byte aligned, start byte copy.
2176 //
2177 UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
2178
2179 if (UnalignedBytes != 0) {
2180 Status = PciIo->Mem.Write (
2181 PciIo,
2182 EfiPciIoWidthUint8,
2183 EFI_PCI_IO_PASS_THROUGH_BAR,
2184 (UINT64) FrameBufferAddr,
2185 UnalignedBytes,
2186 VbeBuffer
2187 );
2188 ASSERT_EFI_ERROR (Status);
2189 FrameBufferAddr += UnalignedBytes;
2190 VbeBuffer += UnalignedBytes;
2191 }
2192
2193 //
2194 // Calculate 4-byte block count and remaining bytes.
2195 //
2196 CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
2197 RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
2198
2199 //
2200 // Copy 4-byte block and remaining bytes to physical frame buffer.
2201 //
2202 if (CopyBlockNum != 0) {
2203 Status = PciIo->Mem.Write (
2204 PciIo,
2205 EfiPciIoWidthUint32,
2206 EFI_PCI_IO_PASS_THROUGH_BAR,
2207 (UINT64) FrameBufferAddr,
2208 CopyBlockNum,
2209 VbeBuffer
2210 );
2211 ASSERT_EFI_ERROR (Status);
2212 }
2213
2214 if (RemainingBytes != 0) {
2215 FrameBufferAddr += (CopyBlockNum << 2);
2216 VbeBuffer += (CopyBlockNum << 2);
2217 Status = PciIo->Mem.Write (
2218 PciIo,
2219 EfiPciIoWidthUint8,
2220 EFI_PCI_IO_PASS_THROUGH_BAR,
2221 (UINT64) FrameBufferAddr,
2222 RemainingBytes,
2223 VbeBuffer
2224 );
2225 ASSERT_EFI_ERROR (Status);
2226 }
2227 }
2228
2229 /**
2230 Worker function to block transfer for VBE device.
2231
2232 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
2233 @param BltBuffer The data to transfer to screen
2234 @param BltOperation The operation to perform
2235 @param SourceX The X coordinate of the source for BltOperation
2236 @param SourceY The Y coordinate of the source for BltOperation
2237 @param DestinationX The X coordinate of the destination for
2238 BltOperation
2239 @param DestinationY The Y coordinate of the destination for
2240 BltOperation
2241 @param Width The width of a rectangle in the blt rectangle in
2242 pixels
2243 @param Height The height of a rectangle in the blt rectangle in
2244 pixels
2245 @param Delta Not used for EfiBltVideoFill and
2246 EfiBltVideoToVideo operation. If a Delta of 0 is
2247 used, the entire BltBuffer will be operated on. If
2248 a subrectangle of the BltBuffer is used, then
2249 Delta represents the number of bytes in a row of
2250 the BltBuffer.
2251 @param Mode Mode data.
2252
2253 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2254 @retval EFI_SUCCESS Blt operation success
2255
2256 **/
2257 EFI_STATUS
2258 BiosVideoVbeBltWorker (
2259 IN BIOS_VIDEO_DEV *BiosVideoPrivate,
2260 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2261 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2262 IN UINTN SourceX,
2263 IN UINTN SourceY,
2264 IN UINTN DestinationX,
2265 IN UINTN DestinationY,
2266 IN UINTN Width,
2267 IN UINTN Height,
2268 IN UINTN Delta,
2269 IN BIOS_VIDEO_MODE_DATA *Mode
2270 )
2271 {
2272 EFI_PCI_IO_PROTOCOL *PciIo;
2273 EFI_TPL OriginalTPL;
2274 UINTN DstY;
2275 UINTN SrcY;
2276 UINTN DstX;
2277 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
2278 VOID *MemAddress;
2279 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
2280 UINTN BytesPerScanLine;
2281 UINTN Index;
2282 UINT8 *VbeBuffer;
2283 UINT8 *VbeBuffer1;
2284 UINT8 *BltUint8;
2285 UINT32 VbePixelWidth;
2286 UINT32 Pixel;
2287 UINTN TotalBytes;
2288
2289 PciIo = BiosVideoPrivate->PciIo;
2290
2291 VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
2292 MemAddress = Mode->LinearFrameBuffer;
2293 BytesPerScanLine = Mode->BytesPerScanLine;
2294 VbePixelWidth = Mode->BitsPerPixel / 8;
2295 BltUint8 = (UINT8 *) BltBuffer;
2296 TotalBytes = Width * VbePixelWidth;
2297
2298 if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2299 return EFI_INVALID_PARAMETER;
2300 }
2301
2302 if (Width == 0 || Height == 0) {
2303 return EFI_INVALID_PARAMETER;
2304 }
2305 //
2306 // We need to fill the Virtual Screen buffer with the blt data.
2307 // The virtual screen is upside down, as the first row is the bootom row of
2308 // the image.
2309 //
2310 if (BltOperation == EfiBltVideoToBltBuffer) {
2311 //
2312 // Video to BltBuffer: Source is Video, destination is BltBuffer
2313 //
2314 if (SourceY + Height > Mode->VerticalResolution) {
2315 return EFI_INVALID_PARAMETER;
2316 }
2317
2318 if (SourceX + Width > Mode->HorizontalResolution) {
2319 return EFI_INVALID_PARAMETER;
2320 }
2321 } else {
2322 //
2323 // BltBuffer to Video: Source is BltBuffer, destination is Video
2324 //
2325 if (DestinationY + Height > Mode->VerticalResolution) {
2326 return EFI_INVALID_PARAMETER;
2327 }
2328
2329 if (DestinationX + Width > Mode->HorizontalResolution) {
2330 return EFI_INVALID_PARAMETER;
2331 }
2332 }
2333 //
2334 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2335 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2336 // the number of bytes in each row can be computed.
2337 //
2338 if (Delta == 0) {
2339 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2340 }
2341 //
2342 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2343 // We would not want a timer based event (Cursor, ...) to come in while we are
2344 // doing this operation.
2345 //
2346 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2347
2348 switch (BltOperation) {
2349 case EfiBltVideoToBltBuffer:
2350 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
2351 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2352 //
2353 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2354 //
2355 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
2356 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2357 Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
2358 Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
2359 Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
2360 Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
2361 Blt->Reserved = 0;
2362 Blt++;
2363 VbeBuffer += VbePixelWidth;
2364 }
2365
2366 }
2367 break;
2368
2369 case EfiBltVideoToVideo:
2370 for (Index = 0; Index < Height; Index++) {
2371 if (DestinationY <= SourceY) {
2372 SrcY = SourceY + Index;
2373 DstY = DestinationY + Index;
2374 } else {
2375 SrcY = SourceY + Height - Index - 1;
2376 DstY = DestinationY + Height - Index - 1;
2377 }
2378
2379 VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
2380 VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
2381
2382 gBS->CopyMem (
2383 VbeBuffer,
2384 VbeBuffer1,
2385 TotalBytes
2386 );
2387
2388 //
2389 // Update physical frame buffer.
2390 //
2391 CopyVideoBuffer (
2392 PciIo,
2393 VbeBuffer,
2394 MemAddress,
2395 DestinationX,
2396 DstY,
2397 TotalBytes,
2398 VbePixelWidth,
2399 BytesPerScanLine
2400 );
2401 }
2402 break;
2403
2404 case EfiBltVideoFill:
2405 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2406 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
2407 //
2408 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2409 //
2410 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2411 (
2412 (Blt->Green & Mode->Green.Mask) <<
2413 Mode->Green.Position
2414 ) |
2415 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2416
2417 for (Index = 0; Index < Width; Index++) {
2418 gBS->CopyMem (
2419 VbeBuffer,
2420 &Pixel,
2421 VbePixelWidth
2422 );
2423 VbeBuffer += VbePixelWidth;
2424 }
2425
2426 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2427 for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
2428 gBS->CopyMem (
2429 (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
2430 VbeBuffer,
2431 TotalBytes
2432 );
2433 }
2434
2435 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
2436 //
2437 // Update physical frame buffer.
2438 //
2439 CopyVideoBuffer (
2440 PciIo,
2441 VbeBuffer,
2442 MemAddress,
2443 DestinationX,
2444 DstY,
2445 TotalBytes,
2446 VbePixelWidth,
2447 BytesPerScanLine
2448 );
2449 }
2450 break;
2451
2452 case EfiBltBufferToVideo:
2453 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
2454 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2455 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2456 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2457 //
2458 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2459 //
2460 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2461 ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
2462 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2463 gBS->CopyMem (
2464 VbeBuffer,
2465 &Pixel,
2466 VbePixelWidth
2467 );
2468 Blt++;
2469 VbeBuffer += VbePixelWidth;
2470 }
2471
2472 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2473
2474 //
2475 // Update physical frame buffer.
2476 //
2477 CopyVideoBuffer (
2478 PciIo,
2479 VbeBuffer,
2480 MemAddress,
2481 DestinationX,
2482 DstY,
2483 TotalBytes,
2484 VbePixelWidth,
2485 BytesPerScanLine
2486 );
2487 }
2488 break;
2489
2490 default: ;
2491 }
2492
2493 gBS->RestoreTPL (OriginalTPL);
2494
2495 return EFI_SUCCESS;
2496 }
2497
2498 /**
2499 Graphics Output protocol instance to block transfer for VBE device.
2500
2501 @param This Pointer to Graphics Output protocol instance
2502 @param BltBuffer The data to transfer to screen
2503 @param BltOperation The operation to perform
2504 @param SourceX The X coordinate of the source for BltOperation
2505 @param SourceY The Y coordinate of the source for BltOperation
2506 @param DestinationX The X coordinate of the destination for
2507 BltOperation
2508 @param DestinationY The Y coordinate of the destination for
2509 BltOperation
2510 @param Width The width of a rectangle in the blt rectangle in
2511 pixels
2512 @param Height The height of a rectangle in the blt rectangle in
2513 pixels
2514 @param Delta Not used for EfiBltVideoFill and
2515 EfiBltVideoToVideo operation. If a Delta of 0 is
2516 used, the entire BltBuffer will be operated on. If
2517 a subrectangle of the BltBuffer is used, then
2518 Delta represents the number of bytes in a row of
2519 the BltBuffer.
2520
2521 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2522 @retval EFI_SUCCESS Blt operation success
2523
2524 **/
2525 EFI_STATUS
2526 EFIAPI
2527 BiosVideoGraphicsOutputVbeBlt (
2528 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
2529 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2530 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2531 IN UINTN SourceX,
2532 IN UINTN SourceY,
2533 IN UINTN DestinationX,
2534 IN UINTN DestinationY,
2535 IN UINTN Width,
2536 IN UINTN Height,
2537 IN UINTN Delta
2538 )
2539 {
2540 BIOS_VIDEO_DEV *BiosVideoPrivate;
2541 BIOS_VIDEO_MODE_DATA *Mode;
2542
2543 if (This == NULL) {
2544 return EFI_INVALID_PARAMETER;
2545 }
2546
2547 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2548 Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode];
2549
2550 return BiosVideoVbeBltWorker (
2551 BiosVideoPrivate,
2552 BltBuffer,
2553 BltOperation,
2554 SourceX,
2555 SourceY,
2556 DestinationX,
2557 DestinationY,
2558 Width,
2559 Height,
2560 Delta,
2561 Mode
2562 );
2563 }
2564
2565 /**
2566 Write graphics controller registers.
2567
2568 @param PciIo Pointer to PciIo protocol instance of the
2569 controller
2570 @param Address Register address
2571 @param Data Data to be written to register
2572
2573 @return None
2574
2575 **/
2576 VOID
2577 WriteGraphicsController (
2578 IN EFI_PCI_IO_PROTOCOL *PciIo,
2579 IN UINTN Address,
2580 IN UINTN Data
2581 )
2582 {
2583 Address = Address | (Data << 8);
2584 PciIo->Io.Write (
2585 PciIo,
2586 EfiPciIoWidthUint16,
2587 EFI_PCI_IO_PASS_THROUGH_BAR,
2588 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
2589 1,
2590 &Address
2591 );
2592 }
2593
2594
2595 /**
2596 Read the four bit plane of VGA frame buffer.
2597
2598 @param PciIo Pointer to PciIo protocol instance of the
2599 controller
2600 @param HardwareBuffer Hardware VGA frame buffer address
2601 @param MemoryBuffer Memory buffer address
2602 @param WidthInBytes Number of bytes in a line to read
2603 @param Height Height of the area to read
2604
2605 @return None
2606
2607 **/
2608 VOID
2609 VgaReadBitPlanes (
2610 EFI_PCI_IO_PROTOCOL *PciIo,
2611 UINT8 *HardwareBuffer,
2612 UINT8 *MemoryBuffer,
2613 UINTN WidthInBytes,
2614 UINTN Height
2615 )
2616 {
2617 UINTN BitPlane;
2618 UINTN Rows;
2619 UINTN FrameBufferOffset;
2620 UINT8 *Source;
2621 UINT8 *Destination;
2622
2623 //
2624 // Program the Mode Register Write mode 0, Read mode 0
2625 //
2626 WriteGraphicsController (
2627 PciIo,
2628 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2629 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2630 );
2631
2632 for (BitPlane = 0, FrameBufferOffset = 0;
2633 BitPlane < VGA_NUMBER_OF_BIT_PLANES;
2634 BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
2635 ) {
2636 //
2637 // Program the Read Map Select Register to select the correct bit plane
2638 //
2639 WriteGraphicsController (
2640 PciIo,
2641 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
2642 BitPlane
2643 );
2644
2645 Source = HardwareBuffer;
2646 Destination = MemoryBuffer + FrameBufferOffset;
2647
2648 for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
2649 PciIo->Mem.Read (
2650 PciIo,
2651 EfiPciIoWidthUint8,
2652 EFI_PCI_IO_PASS_THROUGH_BAR,
2653 (UINT64) (UINTN) Source,
2654 WidthInBytes,
2655 (VOID *) Destination
2656 );
2657 }
2658 }
2659 }
2660
2661
2662 /**
2663 Internal routine to convert VGA color to Grahpics Output color.
2664
2665 @param MemoryBuffer Buffer containing VGA color
2666 @param CoordinateX The X coordinate of pixel on screen
2667 @param CoordinateY The Y coordinate of pixel on screen
2668 @param BltBuffer Buffer to contain converted Grahpics Output color
2669
2670 @return None
2671
2672 **/
2673 VOID
2674 VgaConvertToGraphicsOutputColor (
2675 UINT8 *MemoryBuffer,
2676 UINTN CoordinateX,
2677 UINTN CoordinateY,
2678 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2679 )
2680 {
2681 UINTN Mask;
2682 UINTN Bit;
2683 UINTN Color;
2684
2685 MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
2686 Mask = mVgaBitMaskTable[CoordinateX & 0x07];
2687 for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
2688 if ((*MemoryBuffer & Mask) != 0) {
2689 Color |= Bit;
2690 }
2691 }
2692
2693 *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
2694 }
2695
2696 /**
2697 Internal routine to convert Grahpics Output color to VGA color.
2698
2699 @param BltBuffer buffer containing Grahpics Output color
2700
2701 @return Converted VGA color
2702
2703 **/
2704 UINT8
2705 VgaConvertColor (
2706 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2707 )
2708 {
2709 UINT8 Color;
2710
2711 Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
2712 if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
2713 Color |= 0x08;
2714 }
2715
2716 return Color;
2717 }
2718
2719
2720 /**
2721 Grahpics Output protocol instance to block transfer for VGA device.
2722
2723 @param This Pointer to Grahpics Output protocol instance
2724 @param BltBuffer The data to transfer to screen
2725 @param BltOperation The operation to perform
2726 @param SourceX The X coordinate of the source for BltOperation
2727 @param SourceY The Y coordinate of the source for BltOperation
2728 @param DestinationX The X coordinate of the destination for
2729 BltOperation
2730 @param DestinationY The Y coordinate of the destination for
2731 BltOperation
2732 @param Width The width of a rectangle in the blt rectangle in
2733 pixels
2734 @param Height The height of a rectangle in the blt rectangle in
2735 pixels
2736 @param Delta Not used for EfiBltVideoFill and
2737 EfiBltVideoToVideo operation. If a Delta of 0 is
2738 used, the entire BltBuffer will be operated on. If
2739 a subrectangle of the BltBuffer is used, then
2740 Delta represents the number of bytes in a row of
2741 the BltBuffer.
2742
2743 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2744 @retval EFI_SUCCESS Blt operation success
2745
2746 **/
2747 EFI_STATUS
2748 EFIAPI
2749 BiosVideoGraphicsOutputVgaBlt (
2750 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
2751 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2752 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2753 IN UINTN SourceX,
2754 IN UINTN SourceY,
2755 IN UINTN DestinationX,
2756 IN UINTN DestinationY,
2757 IN UINTN Width,
2758 IN UINTN Height,
2759 IN UINTN Delta
2760 )
2761 {
2762 BIOS_VIDEO_DEV *BiosVideoPrivate;
2763 EFI_TPL OriginalTPL;
2764 UINT8 *MemAddress;
2765 UINTN BytesPerScanLine;
2766 UINTN Bit;
2767 UINTN Index;
2768 UINTN Index1;
2769 UINTN StartAddress;
2770 UINTN Bytes;
2771 UINTN Offset;
2772 UINT8 LeftMask;
2773 UINT8 RightMask;
2774 UINTN Address;
2775 UINTN AddressFix;
2776 UINT8 *Address1;
2777 UINT8 *SourceAddress;
2778 UINT8 *DestinationAddress;
2779 EFI_PCI_IO_PROTOCOL *PciIo;
2780 UINT8 Data;
2781 UINT8 PixelColor;
2782 UINT8 *VgaFrameBuffer;
2783 UINTN SourceOffset;
2784 UINTN SourceWidth;
2785 UINTN Rows;
2786 UINTN Columns;
2787 UINTN CoordinateX;
2788 UINTN CoordinateY;
2789 UINTN CurrentMode;
2790
2791 if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2792 return EFI_INVALID_PARAMETER;
2793 }
2794
2795 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2796
2797 CurrentMode = This->Mode->Mode;
2798 PciIo = BiosVideoPrivate->PciIo;
2799 MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
2800 BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
2801 VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
2802
2803
2804 if (Width == 0 || Height == 0) {
2805 return EFI_INVALID_PARAMETER;
2806 }
2807 //
2808 // We need to fill the Virtual Screen buffer with the blt data.
2809 // The virtual screen is upside down, as the first row is the bootom row of
2810 // the image.
2811 //
2812 if (BltOperation == EfiBltVideoToBltBuffer) {
2813 //
2814 // Video to BltBuffer: Source is Video, destination is BltBuffer
2815 //
2816 if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2817 return EFI_INVALID_PARAMETER;
2818 }
2819
2820 if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2821 return EFI_INVALID_PARAMETER;
2822 }
2823 } else {
2824 //
2825 // BltBuffer to Video: Source is BltBuffer, destination is Video
2826 //
2827 if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2828 return EFI_INVALID_PARAMETER;
2829 }
2830
2831 if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2832 return EFI_INVALID_PARAMETER;
2833 }
2834 }
2835 //
2836 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2837 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2838 // the number of bytes in each row can be computed.
2839 //
2840 if (Delta == 0) {
2841 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2842 }
2843 //
2844 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2845 // We would not want a timer based event (Cursor, ...) to come in while we are
2846 // doing this operation.
2847 //
2848 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2849
2850 //
2851 // Compute some values we need for VGA
2852 //
2853 switch (BltOperation) {
2854 case EfiBltVideoToBltBuffer:
2855
2856 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2857 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2858
2859 //
2860 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2861 //
2862 VgaReadBitPlanes (
2863 PciIo,
2864 MemAddress + SourceOffset,
2865 VgaFrameBuffer + SourceOffset,
2866 SourceWidth,
2867 Height
2868 );
2869
2870 //
2871 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2872 //
2873 BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2874 for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
2875 for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
2876 VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
2877 }
2878
2879 BltBuffer -= Width;
2880 }
2881
2882 break;
2883
2884 case EfiBltVideoToVideo:
2885 //
2886 // Check for an aligned Video to Video operation
2887 //
2888 if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2889 //
2890 // Program the Mode Register Write mode 1, Read mode 0
2891 //
2892 WriteGraphicsController (
2893 PciIo,
2894 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2895 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2896 );
2897
2898 SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2899 DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2900 Bytes = Width >> 3;
2901 for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2902 PciIo->CopyMem (
2903 PciIo,
2904 EfiPciIoWidthUint8,
2905 EFI_PCI_IO_PASS_THROUGH_BAR,
2906 (UINT64) (UINTN) (DestinationAddress + Offset),
2907 EFI_PCI_IO_PASS_THROUGH_BAR,
2908 (UINT64) (UINTN) (SourceAddress + Offset),
2909 Bytes
2910 );
2911 }
2912 } else {
2913 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2914 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2915
2916 //
2917 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2918 //
2919 VgaReadBitPlanes (
2920 PciIo,
2921 MemAddress + SourceOffset,
2922 VgaFrameBuffer + SourceOffset,
2923 SourceWidth,
2924 Height
2925 );
2926 }
2927
2928 break;
2929
2930 case EfiBltVideoFill:
2931 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2932 Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2933 LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
2934 RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2935 if (Bytes == 0) {
2936 LeftMask = (UINT8) (LeftMask & RightMask);
2937 RightMask = 0;
2938 }
2939
2940 if (LeftMask == 0xff) {
2941 StartAddress--;
2942 Bytes++;
2943 LeftMask = 0;
2944 }
2945
2946 if (RightMask == 0xff) {
2947 Bytes++;
2948 RightMask = 0;
2949 }
2950
2951 PixelColor = VgaConvertColor (BltBuffer);
2952
2953 //
2954 // Program the Mode Register Write mode 2, Read mode 0
2955 //
2956 WriteGraphicsController (
2957 PciIo,
2958 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2959 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2960 );
2961
2962 //
2963 // Program the Data Rotate/Function Select Register to replace
2964 //
2965 WriteGraphicsController (
2966 PciIo,
2967 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2968 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2969 );
2970
2971 if (LeftMask != 0) {
2972 //
2973 // Program the BitMask register with the Left column mask
2974 //
2975 WriteGraphicsController (
2976 PciIo,
2977 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2978 LeftMask
2979 );
2980
2981 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2982 //
2983 // Read data from the bit planes into the latches
2984 //
2985 PciIo->Mem.Read (
2986 PciIo,
2987 EfiPciIoWidthUint8,
2988 EFI_PCI_IO_PASS_THROUGH_BAR,
2989 (UINT64) (UINTN) Address,
2990 1,
2991 &Data
2992 );
2993 //
2994 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2995 //
2996 PciIo->Mem.Write (
2997 PciIo,
2998 EfiPciIoWidthUint8,
2999 EFI_PCI_IO_PASS_THROUGH_BAR,
3000 (UINT64) (UINTN) Address,
3001 1,
3002 &PixelColor
3003 );
3004 }
3005 }
3006
3007 if (Bytes > 1) {
3008 //
3009 // Program the BitMask register with the middle column mask of 0xff
3010 //
3011 WriteGraphicsController (
3012 PciIo,
3013 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3014 0xff
3015 );
3016
3017 for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
3018 PciIo->Mem.Write (
3019 PciIo,
3020 EfiPciIoWidthFillUint8,
3021 EFI_PCI_IO_PASS_THROUGH_BAR,
3022 (UINT64) (UINTN) Address,
3023 Bytes - 1,
3024 &PixelColor
3025 );
3026 }
3027 }
3028
3029 if (RightMask != 0) {
3030 //
3031 // Program the BitMask register with the Right column mask
3032 //
3033 WriteGraphicsController (
3034 PciIo,
3035 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3036 RightMask
3037 );
3038
3039 for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
3040 //
3041 // Read data from the bit planes into the latches
3042 //
3043 PciIo->Mem.Read (
3044 PciIo,
3045 EfiPciIoWidthUint8,
3046 EFI_PCI_IO_PASS_THROUGH_BAR,
3047 (UINT64) (UINTN) Address,
3048 1,
3049 &Data
3050 );
3051 //
3052 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3053 //
3054 PciIo->Mem.Write (
3055 PciIo,
3056 EfiPciIoWidthUint8,
3057 EFI_PCI_IO_PASS_THROUGH_BAR,
3058 (UINT64) (UINTN) Address,
3059 1,
3060 &PixelColor
3061 );
3062 }
3063 }
3064 break;
3065
3066 case EfiBltBufferToVideo:
3067 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
3068 LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
3069
3070 //
3071 // Program the Mode Register Write mode 2, Read mode 0
3072 //
3073 WriteGraphicsController (
3074 PciIo,
3075 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
3076 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3077 );
3078
3079 //
3080 // Program the Data Rotate/Function Select Register to replace
3081 //
3082 WriteGraphicsController (
3083 PciIo,
3084 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
3085 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3086 );
3087
3088 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
3089 for (Index1 = 0; Index1 < Width; Index1++) {
3090 BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
3091 }
3092 AddressFix = Address;
3093
3094 for (Bit = 0; Bit < 8; Bit++) {
3095 //
3096 // Program the BitMask register with the Left column mask
3097 //
3098 WriteGraphicsController (
3099 PciIo,
3100 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
3101 LeftMask
3102 );
3103
3104 for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
3105 //
3106 // Read data from the bit planes into the latches
3107 //
3108 PciIo->Mem.Read (
3109 PciIo,
3110 EfiPciIoWidthUint8,
3111 EFI_PCI_IO_PASS_THROUGH_BAR,
3112 (UINT64) (UINTN) Address1,
3113 1,
3114 &Data
3115 );
3116
3117 PciIo->Mem.Write (
3118 PciIo,
3119 EfiPciIoWidthUint8,
3120 EFI_PCI_IO_PASS_THROUGH_BAR,
3121 (UINT64) (UINTN) Address1,
3122 1,
3123 &BiosVideoPrivate->LineBuffer[Index1]
3124 );
3125 }
3126
3127 LeftMask = (UINT8) (LeftMask >> 1);
3128 if (LeftMask == 0) {
3129 LeftMask = 0x80;
3130 AddressFix++;
3131 }
3132 }
3133 }
3134
3135 break;
3136
3137 default: ;
3138 }
3139
3140 gBS->RestoreTPL (OriginalTPL);
3141
3142 return EFI_SUCCESS;
3143 }
3144
3145 //
3146 // VGA Mini Port Protocol Functions
3147 //
3148
3149 /**
3150 VgaMiniPort protocol interface to set mode.
3151
3152 @param This Pointer to VgaMiniPort protocol instance
3153 @param ModeNumber The index of the mode
3154
3155 @retval EFI_UNSUPPORTED The requested mode is not supported
3156 @retval EFI_SUCCESS The requested mode is set successfully
3157
3158 **/
3159 EFI_STATUS
3160 EFIAPI
3161 BiosVideoVgaMiniPortSetMode (
3162 IN EFI_VGA_MINI_PORT_PROTOCOL *This,
3163 IN UINTN ModeNumber
3164 )
3165 {
3166 BIOS_VIDEO_DEV *BiosVideoPrivate;
3167 EFI_IA32_REGISTER_SET Regs;
3168
3169 if (This == NULL) {
3170 return EFI_INVALID_PARAMETER;
3171 }
3172
3173 //
3174 // Make sure the ModeNumber is a valid value
3175 //
3176 if (ModeNumber >= This->MaxMode) {
3177 return EFI_UNSUPPORTED;
3178 }
3179 //
3180 // Get the device structure for this device
3181 //
3182 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
3183
3184 switch (ModeNumber) {
3185 case 0:
3186 //
3187 // Set the 80x25 Text VGA Mode
3188 //
3189 Regs.H.AH = 0x00;
3190 Regs.H.AL = 0x83;
3191 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3192
3193 Regs.H.AH = 0x11;
3194 Regs.H.AL = 0x14;
3195 Regs.H.BL = 0;
3196 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3197 break;
3198
3199 case 1:
3200 //
3201 // Set the 80x50 Text VGA Mode
3202 //
3203 Regs.H.AH = 0x00;
3204 Regs.H.AL = 0x83;
3205 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3206 Regs.H.AH = 0x11;
3207 Regs.H.AL = 0x12;
3208 Regs.H.BL = 0;
3209 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3210 break;
3211
3212 default:
3213 return EFI_UNSUPPORTED;
3214 }
3215
3216 return EFI_SUCCESS;
3217 }
3218
3219 /**
3220 Event handler for Exit Boot Service.
3221
3222 @param Event The event that be siganlled when exiting boot service.
3223 @param Context Pointer to instance of BIOS_VIDEO_DEV.
3224
3225 **/
3226 VOID
3227 EFIAPI
3228 BiosVideoNotifyExitBootServices (
3229 IN EFI_EVENT Event,
3230 IN VOID *Context
3231 )
3232 {
3233 BIOS_VIDEO_DEV *BiosVideoPrivate;
3234 EFI_IA32_REGISTER_SET Regs;
3235
3236 BiosVideoPrivate = (BIOS_VIDEO_DEV *)Context;
3237
3238 //
3239 // Set the 80x25 Text VGA Mode
3240 //
3241 Regs.H.AH = 0x00;
3242 Regs.H.AL = 0x03;
3243 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3244
3245 Regs.H.AH = 0x00;
3246 Regs.H.AL = 0x83;
3247 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3248
3249 Regs.H.AH = 0x11;
3250 Regs.H.AL = 0x04;
3251 Regs.H.BL = 0;
3252 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
3253 }
3254
3255 /**
3256 The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3257
3258 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3259 @param[in] SystemTable A pointer to the EFI System Table.
3260
3261 @retval EFI_SUCCESS The entry point is executed successfully.
3262 @retval other Some error occurs when executing this entry point.
3263
3264 **/
3265 EFI_STATUS
3266 EFIAPI
3267 BiosVideoEntryPoint(
3268 IN EFI_HANDLE ImageHandle,
3269 IN EFI_SYSTEM_TABLE *SystemTable
3270 )
3271 {
3272 EFI_STATUS Status;
3273
3274 //
3275 // Install driver model protocol(s).
3276 //
3277 Status = EfiLibInstallDriverBindingComponentName2 (
3278 ImageHandle,
3279 SystemTable,
3280 &gBiosVideoDriverBinding,
3281 ImageHandle,
3282 &gBiosVideoComponentName,
3283 &gBiosVideoComponentName2
3284 );
3285 ASSERT_EFI_ERROR (Status);
3286
3287 //
3288 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3289 //
3290 return gBS->InstallMultipleProtocolInterfaces (
3291 &ImageHandle,
3292 &gEfiLegacyBiosGuid,
3293 NULL,
3294 NULL
3295 );
3296 }
3297