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