1 /*++
2 
3 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   Graphics.c
15 
16 Abstract:
17 
18   Support for Basic Graphics operations.
19 
20   BugBug: Currently *.BMP files are supported. This will be replaced
21           when Tiano graphics format is supported.
22 
23 --*/
24 
25 #include "Tiano.h"
26 #include "EfiDriverLib.h"
27 #include "GraphicsLib.h"
28 
29 
30 EFI_STATUS
GetGraphicsBitMapFromFV(IN EFI_GUID * FileNameGuid,OUT VOID ** Image,OUT UINTN * ImageSize)31 GetGraphicsBitMapFromFV (
32   IN  EFI_GUID      *FileNameGuid,
33   OUT VOID          **Image,
34   OUT UINTN         *ImageSize
35   )
36 /*++
37 
38 Routine Description:
39 
40   Return the graphics image file named FileNameGuid into Image and return it's
41   size in ImageSize. All Firmware Volumes (FV) in the system are searched for the
42   file name.
43 
44 Arguments:
45 
46   FileNameGuid  - File Name of graphics file in the FV(s).
47 
48   Image         - Pointer to pointer to return graphics image.  If NULL, a
49                   buffer will be allocated.
50 
51   ImageSize     - Size of the graphics Image in bytes. Zero if no image found.
52 
53 
54 Returns:
55 
56   EFI_SUCCESS          - Image and ImageSize are valid.
57   EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size
58   EFI_NOT_FOUND        - FileNameGuid not found
59 
60 --*/
61 {
62   return GetGraphicsBitMapFromFVEx (NULL, FileNameGuid, Image, ImageSize);
63 }
64 
65 EFI_STATUS
GetGraphicsBitMapFromFVEx(IN EFI_HANDLE ImageHandle,IN EFI_GUID * FileNameGuid,OUT VOID ** Image,OUT UINTN * ImageSize)66 GetGraphicsBitMapFromFVEx (
67   IN  EFI_HANDLE    ImageHandle,
68   IN  EFI_GUID      *FileNameGuid,
69   OUT VOID          **Image,
70   OUT UINTN         *ImageSize
71   )
72 /*++
73 
74 Routine Description:
75 
76   Return the graphics image file named FileNameGuid into Image and return it's
77   size in ImageSize. All Firmware Volumes (FV) in the system are searched for the
78   file name.
79 
80 Arguments:
81 
82   ImageHandle   - The driver image handle of the caller. The parameter is used to
83                   optimize the loading of the image file so that the FV from which
84                   the driver image is loaded will be tried first.
85 
86   FileNameGuid  - File Name of graphics file in the FV(s).
87 
88   Image         - Pointer to pointer to return graphics image.  If NULL, a
89                   buffer will be allocated.
90 
91   ImageSize     - Size of the graphics Image in bytes. Zero if no image found.
92 
93 
94 Returns:
95 
96   EFI_SUCCESS          - Image and ImageSize are valid.
97   EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size
98   EFI_NOT_FOUND        - FileNameGuid not found
99 
100 --*/
101 {
102   return GetImageEx (
103            ImageHandle,
104            FileNameGuid,
105            EFI_SECTION_RAW,
106            Image,
107            ImageSize,
108            FALSE
109            );
110 }
111 
112 
113 EFI_STATUS
ConvertBmpToGopBlt(IN VOID * BmpImage,IN UINTN BmpImageSize,IN OUT VOID ** GopBlt,IN OUT UINTN * GopBltSize,OUT UINTN * PixelHeight,OUT UINTN * PixelWidth)114 ConvertBmpToGopBlt (
115   IN  VOID      *BmpImage,
116   IN  UINTN     BmpImageSize,
117   IN OUT VOID   **GopBlt,
118   IN OUT UINTN  *GopBltSize,
119   OUT UINTN     *PixelHeight,
120   OUT UINTN     *PixelWidth
121   )
122 /*++
123 
124 Routine Description:
125 
126   Convert a *.BMP graphics image to a GOP/UGA blt buffer. If a NULL Blt buffer
127   is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
128   buffer is passed in it will be used if it is big enough.
129 
130 Arguments:
131 
132   BmpImage      - Pointer to BMP file
133 
134   BmpImageSize  - Number of bytes in BmpImage
135 
136   GopBlt        - Buffer containing GOP version of BmpImage.
137 
138   GopBltSize    - Size of GopBlt in bytes.
139 
140   PixelHeight   - Height of GopBlt/BmpImage in pixels
141 
142   PixelWidth    - Width of GopBlt/BmpImage in pixels
143 
144 
145 Returns:
146 
147   EFI_SUCCESS           - GopBlt and GopBltSize are returned.
148   EFI_UNSUPPORTED       - BmpImage is not a valid *.BMP image
149   EFI_BUFFER_TOO_SMALL  - The passed in GopBlt buffer is not big enough.
150                           GopBltSize will contain the required size.
151   EFI_OUT_OF_RESOURCES  - No enough buffer to allocate
152 
153 --*/
154 {
155   UINT8                         *Image;
156   UINT8                         *ImageHeader;
157   BMP_IMAGE_HEADER              *BmpHeader;
158   BMP_COLOR_MAP                 *BmpColorMap;
159   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
160   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
161   UINT64                        BltBufferSize;
162   UINTN                         Index;
163   UINTN                         Height;
164   UINTN                         Width;
165   UINTN                         ImageIndex;
166   UINTN                         DataSizePerLine;
167   BOOLEAN                       IsAllocated;
168   UINT32                        ColorMapNum;
169 
170   if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
171     return EFI_INVALID_PARAMETER;
172   }
173 
174   BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
175 
176   if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
177     return EFI_UNSUPPORTED;
178   }
179 
180   //
181   // Doesn't support compress.
182   //
183   if (BmpHeader->CompressionType != 0) {
184     return EFI_UNSUPPORTED;
185   }
186 
187   //
188   // Only support BITMAPINFOHEADER format.
189   // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
190   //
191   if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - ((UINTN) &(((BMP_IMAGE_HEADER *)0)->HeaderSize))) {
192     return EFI_UNSUPPORTED;
193   }
194 
195   //
196   // The data size in each line must be 4 byte alignment.
197   //
198   DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
199   BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
200   if (BltBufferSize > (UINT32) ~0) {
201     return EFI_INVALID_PARAMETER;
202   }
203 
204   if ((BmpHeader->Size != BmpImageSize) ||
205       (BmpHeader->Size < BmpHeader->ImageOffset) ||
206       (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
207     return EFI_INVALID_PARAMETER;
208   }
209 
210   //
211   // Calculate Color Map offset in the image.
212   //
213   Image       = BmpImage;
214   BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
215   if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
216     return EFI_INVALID_PARAMETER;
217   }
218 
219   if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
220     switch (BmpHeader->BitPerPixel) {
221       case 1:
222         ColorMapNum = 2;
223         break;
224       case 4:
225         ColorMapNum = 16;
226         break;
227       case 8:
228         ColorMapNum = 256;
229         break;
230       default:
231         ColorMapNum = 0;
232         break;
233       }
234     if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) != sizeof (BMP_COLOR_MAP) * ColorMapNum) {
235       return EFI_INVALID_PARAMETER;
236     }
237   }
238 
239   //
240   // Calculate graphics image data address in the image
241   //
242   Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
243   ImageHeader   = Image;
244 
245   BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
246   //
247   // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
248   //
249   if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), NULL)) {
250      return EFI_UNSUPPORTED;
251   }
252   BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
253 
254   IsAllocated   = FALSE;
255   if (*GopBlt == NULL) {
256     *GopBltSize = (UINTN) BltBufferSize;
257     *GopBlt     = EfiLibAllocatePool (*GopBltSize);
258     IsAllocated = TRUE;
259     if (*GopBlt == NULL) {
260       return EFI_OUT_OF_RESOURCES;
261     }
262   } else {
263     if (*GopBltSize < (UINTN) BltBufferSize) {
264       *GopBltSize = (UINTN) BltBufferSize;
265       return EFI_BUFFER_TOO_SMALL;
266     }
267   }
268 
269   *PixelWidth   = BmpHeader->PixelWidth;
270   *PixelHeight  = BmpHeader->PixelHeight;
271 
272   //
273   // Convert image from BMP to Blt buffer format
274   //
275   BltBuffer = *GopBlt;
276   for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
277     Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
278     for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
279       switch (BmpHeader->BitPerPixel) {
280       case 1:
281         //
282         // Convert 1bit BMP to 24-bit color
283         //
284         for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
285           Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
286           Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
287           Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
288           Blt++;
289           Width++;
290         }
291 
292         Blt --;
293         Width --;
294         break;
295 
296       case 4:
297         //
298         // Convert BMP Palette to 24-bit color
299         //
300         Index       = (*Image) >> 4;
301         Blt->Red    = BmpColorMap[Index].Red;
302         Blt->Green  = BmpColorMap[Index].Green;
303         Blt->Blue   = BmpColorMap[Index].Blue;
304         if (Width < (BmpHeader->PixelWidth - 1)) {
305           Blt++;
306           Width++;
307           Index       = (*Image) & 0x0f;
308           Blt->Red    = BmpColorMap[Index].Red;
309           Blt->Green  = BmpColorMap[Index].Green;
310           Blt->Blue   = BmpColorMap[Index].Blue;
311         }
312         break;
313 
314       case 8:
315         //
316         // Convert BMP Palette to 24-bit color
317         //
318         Blt->Red    = BmpColorMap[*Image].Red;
319         Blt->Green  = BmpColorMap[*Image].Green;
320         Blt->Blue   = BmpColorMap[*Image].Blue;
321         break;
322 
323       case 24:
324         Blt->Blue   = *Image++;
325         Blt->Green  = *Image++;
326         Blt->Red    = *Image;
327         break;
328 
329       default:
330         if (IsAllocated) {
331           gBS->FreePool (*GopBlt);
332           *GopBlt = NULL;
333         }
334         return EFI_UNSUPPORTED;
335         break;
336       };
337 
338     }
339 
340     ImageIndex = (UINTN) (Image - ImageHeader);
341     if ((ImageIndex % 4) != 0) {
342       //
343       // Bmp Image starts each row on a 32-bit boundary!
344       //
345       Image = Image + (4 - (ImageIndex % 4));
346     }
347   }
348 
349   return EFI_SUCCESS;
350 }
351 
352 
353 EFI_STATUS
LockKeyboards(IN CHAR16 * Password)354 LockKeyboards (
355   IN  CHAR16    *Password
356   )
357 /*++
358 
359 Routine Description:
360   Use Console Control Protocol to lock the Console In Spliter virtual handle.
361   This is the ConInHandle and ConIn handle in the EFI system table. All key
362   presses will be ignored until the Password is typed in. The only way to
363   disable the password is to type it in to a ConIn device.
364 
365 Arguments:
366   Password - Password used to lock ConIn device
367 
368 
369 Returns:
370 
371   EFI_SUCCESS     - ConsoleControl has been flipped to graphics and logo
372                           displayed.
373   EFI_UNSUPPORTED - Logo not found
374 
375 --*/
376 {
377   EFI_STATUS                    Status;
378   EFI_CONSOLE_CONTROL_PROTOCOL  *ConsoleControl;
379 
380   Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
381   if (EFI_ERROR (Status)) {
382     return EFI_UNSUPPORTED;
383   }
384 
385   Status = ConsoleControl->LockStdIn (ConsoleControl, Password);
386   return Status;
387 }
388 
389 EFI_STATUS
EnableQuietBoot(IN EFI_GUID * LogoFile)390 EnableQuietBoot (
391   IN  EFI_GUID  *LogoFile
392   )
393 /*++
394 
395 Routine Description:
396 
397   Use Console Control to turn off UGA based Simple Text Out consoles from going
398   to the UGA device. Put up LogoFile on every UGA device that is a console
399 
400 Arguments:
401 
402   LogoFile - File name of logo to display on the center of the screen.
403 
404 
405 Returns:
406 
407   EFI_SUCCESS           - ConsoleControl has been flipped to graphics and logo
408                           displayed.
409   EFI_UNSUPPORTED       - Logo not found
410 
411 --*/
412 {
413   return EnableQuietBootEx (LogoFile, NULL);
414 }
415 
416 
417 EFI_STATUS
EnableQuietBootEx(IN EFI_GUID * LogoFile,IN EFI_HANDLE ImageHandle)418 EnableQuietBootEx (
419   IN  EFI_GUID    *LogoFile,
420   IN  EFI_HANDLE  ImageHandle
421   )
422 /*++
423 
424 Routine Description:
425 
426   Use Console Control to turn off GOP/UGA based Simple Text Out consoles from going
427   to the GOP/UGA device. Put up LogoFile on every GOP/UGA device that is a console
428 
429 Arguments:
430 
431   LogoFile - File name of logo to display on the center of the screen.
432 
433 
434 Returns:
435 
436   EFI_SUCCESS           - ConsoleControl has been flipped to graphics and logo
437                           displayed.
438   EFI_UNSUPPORTED       - Logo not found
439 
440 --*/
441 {
442   EFI_STATUS                    Status;
443   EFI_CONSOLE_CONTROL_PROTOCOL  *ConsoleControl;
444   EFI_OEM_BADGING_PROTOCOL      *Badging;
445   UINT32                        SizeOfX;
446   UINT32                        SizeOfY;
447   INTN                          DestX;
448   INTN                          DestY;
449   UINT8                         *ImageData;
450   UINTN                         ImageSize;
451   UINTN                         BltSize;
452   UINT32                        Instance;
453   EFI_BADGING_FORMAT            Format;
454   EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
455   UINTN                         CoordinateX;
456   UINTN                         CoordinateY;
457   UINTN                         Height;
458   UINTN                         Width;
459   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
460   EFI_UGA_DRAW_PROTOCOL         *UgaDraw;
461   UINT32                        ColorDepth;
462   UINT32                        RefreshRate;
463   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
464 
465   Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
466   if (EFI_ERROR (Status)) {
467     return EFI_UNSUPPORTED;
468   }
469 
470   UgaDraw = NULL;
471   //
472   // Try to open GOP first
473   //
474   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
475   if (EFI_ERROR (Status)) {
476     GraphicsOutput = NULL;
477     //
478     // Open GOP failed, try to open UGA
479     //
480     Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
481     if (EFI_ERROR (Status)) {
482       return EFI_UNSUPPORTED;
483     }
484   }
485 
486   Badging = NULL;
487   Status  = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
488 
489   ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenGraphics);
490 
491   if (GraphicsOutput != NULL) {
492     SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
493     SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
494   } else if (UgaDraw != NULL) {
495     Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
496     if (EFI_ERROR (Status)) {
497       return EFI_UNSUPPORTED;
498     }
499   } else {
500     return EFI_UNSUPPORTED;
501   }
502 
503   Instance = 0;
504   while (1) {
505     ImageData = NULL;
506     ImageSize = 0;
507 
508     if (Badging != NULL) {
509       Status = Badging->GetImage (
510                           Badging,
511                           &Instance,
512                           &Format,
513                           &ImageData,
514                           &ImageSize,
515                           &Attribute,
516                           &CoordinateX,
517                           &CoordinateY
518                           );
519       if (EFI_ERROR (Status)) {
520         return Status;
521       }
522 
523       //
524       // Currently only support BMP format
525       //
526       if (Format != EfiBadgingFormatBMP) {
527         gBS->FreePool (ImageData);
528         continue;
529       }
530     } else {
531       Status = GetGraphicsBitMapFromFVEx (ImageHandle, LogoFile, (VOID **) &ImageData, &ImageSize);
532       if (EFI_ERROR (Status)) {
533         return EFI_UNSUPPORTED;
534       }
535 
536       CoordinateX = 0;
537       CoordinateY = 0;
538       Attribute   = EfiBadgingDisplayAttributeCenter;
539     }
540 
541     Blt = NULL;
542     Status = ConvertBmpToGopBlt (
543               ImageData,
544               ImageSize,
545               (VOID **) &Blt,
546               &BltSize,
547               &Height,
548               &Width
549               );
550     if (EFI_ERROR (Status)) {
551       gBS->FreePool (ImageData);
552       if (Badging == NULL) {
553         return Status;
554       } else {
555         continue;
556       }
557     }
558 
559     switch (Attribute) {
560     case EfiBadgingDisplayAttributeLeftTop:
561       DestX = CoordinateX;
562       DestY = CoordinateY;
563       break;
564 
565     case EfiBadgingDisplayAttributeCenterTop:
566       DestX = (SizeOfX - Width) / 2;
567       DestY = CoordinateY;
568       break;
569 
570     case EfiBadgingDisplayAttributeRightTop:
571       DestX = (SizeOfX - Width - CoordinateX);
572       DestY = CoordinateY;;
573       break;
574 
575     case EfiBadgingDisplayAttributeCenterRight:
576       DestX = (SizeOfX - Width - CoordinateX);
577       DestY = (SizeOfY - Height) / 2;
578       break;
579 
580     case EfiBadgingDisplayAttributeRightBottom:
581       DestX = (SizeOfX - Width - CoordinateX);
582       DestY = (SizeOfY - Height - CoordinateY);
583       break;
584 
585     case EfiBadgingDisplayAttributeCenterBottom:
586       DestX = (SizeOfX - Width) / 2;
587       DestY = (SizeOfY - Height - CoordinateY);
588       break;
589 
590     case EfiBadgingDisplayAttributeLeftBottom:
591       DestX = CoordinateX;
592       DestY = (SizeOfY - Height - CoordinateY);
593       break;
594 
595     case EfiBadgingDisplayAttributeCenterLeft:
596       DestX = CoordinateX;
597       DestY = (SizeOfY - Height) / 2;
598       break;
599 
600     case EfiBadgingDisplayAttributeCenter:
601       DestX = (SizeOfX - Width) / 2;
602       DestY = (SizeOfY - Height) / 2;
603       break;
604 
605     default:
606       DestX = CoordinateX;
607       DestY = CoordinateY;
608       break;
609     }
610 
611     if ((DestX >= 0) && (DestY >= 0)) {
612       if (GraphicsOutput != NULL) {
613         Status = GraphicsOutput->Blt (
614                             GraphicsOutput,
615                             Blt,
616                             EfiBltBufferToVideo,
617                             0,
618                             0,
619                             (UINTN) DestX,
620                             (UINTN) DestY,
621                             Width,
622                             Height,
623                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
624                             );
625       } else {
626         Status = UgaDraw->Blt (
627                             UgaDraw,
628                             (EFI_UGA_PIXEL *) Blt,
629                             EfiUgaBltBufferToVideo,
630                             0,
631                             0,
632                             (UINTN) DestX,
633                             (UINTN) DestY,
634                             Width,
635                             Height,
636                             Width * sizeof (EFI_UGA_PIXEL)
637                             );
638       }
639     }
640 
641     gBS->FreePool (ImageData);
642     gBS->FreePool (Blt);
643 
644     if (Badging == NULL) {
645       break;
646     }
647   }
648 
649   return Status;
650 }
651 
652 
653 EFI_STATUS
DisableQuietBoot(VOID)654 DisableQuietBoot (
655   VOID
656   )
657 /*++
658 
659 Routine Description:
660 
661   Use Console Control to turn on GOP/UGA based Simple Text Out consoles. The GOP/UGA
662   Simple Text Out screens will now be synced up with all non GOP/UGA output devices
663 
664 Arguments:
665 
666   NONE
667 
668 Returns:
669 
670   EFI_SUCCESS           - GOP/UGA devices are back in text mode and synced up.
671   EFI_UNSUPPORTED       - Logo not found
672 
673 --*/
674 {
675   EFI_STATUS                    Status;
676   EFI_CONSOLE_CONTROL_PROTOCOL  *ConsoleControl;
677 
678   Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
679   if (EFI_ERROR (Status)) {
680     return EFI_UNSUPPORTED;
681   }
682 
683   return ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText);
684 }
685