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