1 /** @file
2   This module install ACPI Boot Graphics Resource Table (BGRT).
3 
4   Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13 
14 #include <Uefi.h>
15 
16 #include <IndustryStandard/Acpi.h>
17 #include <IndustryStandard/Bmp.h>
18 
19 #include <Protocol/AcpiTable.h>
20 #include <Protocol/GraphicsOutput.h>
21 #include <Protocol/BootLogo.h>
22 
23 #include <Guid/EventGroup.h>
24 
25 #include <Library/BaseLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/PcdLib.h>
31 
32 //
33 // Module globals.
34 //
35 EFI_EVENT  mBootGraphicsReadyToBootEvent;
36 UINTN      mBootGraphicsResourceTableKey = 0;
37 
38 EFI_HANDLE                     mBootLogoHandle = NULL;
39 BOOLEAN                        mIsLogoValid = FALSE;
40 EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *mLogoBltBuffer = NULL;
41 UINTN                          mLogoDestX = 0;
42 UINTN                          mLogoDestY = 0;
43 UINTN                          mLogoWidth = 0;
44 UINTN                          mLogoHeight = 0;
45 
46 BMP_IMAGE_HEADER  mBmpImageHeaderTemplate = {
47   'B',    // CharB
48   'M',    // CharM
49   0,      // Size will be updated at runtime
50   {0, 0}, // Reserved
51   sizeof (BMP_IMAGE_HEADER), // ImageOffset
52   sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
53   0,      // PixelWidth will be updated at runtime
54   0,      // PixelHeight will be updated at runtime
55   1,      // Planes
56   24,     // BitPerPixel
57   0,      // CompressionType
58   0,      // ImageSize will be updated at runtime
59   0,      // XPixelsPerMeter
60   0,      // YPixelsPerMeter
61   0,      // NumberOfColors
62   0       // ImportantColors
63 };
64 
65 BOOLEAN  mAcpiBgrtInstalled = FALSE;
66 BOOLEAN  mAcpiBgrtStatusChanged = FALSE;
67 BOOLEAN  mAcpiBgrtBufferChanged = FALSE;
68 
69 EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE mBootGraphicsResourceTableTemplate = {
70   {
71     EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE,
72     sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
73     EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE_REVISION,     // Revision
74     0x00,  // Checksum will be updated at runtime
75     //
76     // It is expected that these values will be updated at EntryPoint.
77     //
78     {0x00},     // OEM ID is a 6 bytes long field
79     0x00,       // OEM Table ID(8 bytes long)
80     0x00,       // OEM Revision
81     0x00,       // Creator ID
82     0x00,       // Creator Revision
83   },
84   EFI_ACPI_5_0_BGRT_VERSION,         // Version
85   EFI_ACPI_5_0_BGRT_STATUS_VALID,    // Status
86   EFI_ACPI_5_0_BGRT_IMAGE_TYPE_BMP,  // Image Type
87   0,                                 // Image Address
88   0,                                 // Image Offset X
89   0                                  // Image Offset Y
90 };
91 
92 /**
93   Update information of logo image drawn on screen.
94 
95   @param  This           The pointer to the Boot Logo protocol instance.
96   @param  BltBuffer      The BLT buffer for logo drawn on screen. If BltBuffer
97                          is set to NULL, it indicates that logo image is no
98                          longer on the screen.
99   @param  DestinationX   X coordinate of destination for the BltBuffer.
100   @param  DestinationY   Y coordinate of destination for the BltBuffer.
101   @param  Width          Width of rectangle in BltBuffer in pixels.
102   @param  Height         Hight of rectangle in BltBuffer in pixels.
103 
104   @retval EFI_SUCCESS             The boot logo information was updated.
105   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
106   @retval EFI_OUT_OF_RESOURCES    The logo information was not updated due to
107                                   insufficient memory resources.
108 
109 **/
110 EFI_STATUS
111 EFIAPI
112 SetBootLogo (
113   IN EFI_BOOT_LOGO_PROTOCOL            *This,
114   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer       OPTIONAL,
115   IN UINTN                             DestinationX,
116   IN UINTN                             DestinationY,
117   IN UINTN                             Width,
118   IN UINTN                             Height
119   );
120 
121 EFI_BOOT_LOGO_PROTOCOL  mBootLogoProtocolTemplate = { SetBootLogo };
122 
123 /**
124   Update information of logo image drawn on screen.
125 
126   @param  This           The pointer to the Boot Logo protocol instance.
127   @param  BltBuffer      The BLT buffer for logo drawn on screen. If BltBuffer
128                          is set to NULL, it indicates that logo image is no
129                          longer on the screen.
130   @param  DestinationX   X coordinate of destination for the BltBuffer.
131   @param  DestinationY   Y coordinate of destination for the BltBuffer.
132   @param  Width          Width of rectangle in BltBuffer in pixels.
133   @param  Height         Hight of rectangle in BltBuffer in pixels.
134 
135   @retval EFI_SUCCESS             The boot logo information was updated.
136   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
137   @retval EFI_OUT_OF_RESOURCES    The logo information was not updated due to
138                                   insufficient memory resources.
139 
140 **/
141 EFI_STATUS
142 EFIAPI
SetBootLogo(IN EFI_BOOT_LOGO_PROTOCOL * This,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer OPTIONAL,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height)143 SetBootLogo (
144   IN EFI_BOOT_LOGO_PROTOCOL            *This,
145   IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer       OPTIONAL,
146   IN UINTN                             DestinationX,
147   IN UINTN                             DestinationY,
148   IN UINTN                             Width,
149   IN UINTN                             Height
150   )
151 {
152   UINT64                        BufferSize;
153 
154   if (BltBuffer == NULL) {
155     mIsLogoValid = FALSE;
156     mAcpiBgrtStatusChanged = TRUE;
157     return EFI_SUCCESS;
158   }
159 
160   if (Width == 0 || Height == 0) {
161     return EFI_INVALID_PARAMETER;
162   }
163 
164   mAcpiBgrtBufferChanged = TRUE;
165   if (mLogoBltBuffer != NULL) {
166     FreePool (mLogoBltBuffer);
167     mLogoBltBuffer = NULL;
168   }
169 
170   //
171   // Ensure the Height * Width doesn't overflow
172   //
173   if (Height > DivU64x64Remainder ((UINTN) ~0, Width, NULL)) {
174     return EFI_UNSUPPORTED;
175   }
176   BufferSize = MultU64x64 (Width, Height);
177 
178   //
179   // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
180   //
181   if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
182     return EFI_UNSUPPORTED;
183   }
184 
185   mLogoBltBuffer = AllocateCopyPool (
186                      (UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
187                      BltBuffer
188                      );
189   if (mLogoBltBuffer == NULL) {
190     return EFI_OUT_OF_RESOURCES;
191   }
192   mLogoDestX = DestinationX;
193   mLogoDestY = DestinationY;
194   mLogoWidth = Width;
195   mLogoHeight = Height;
196   mIsLogoValid = TRUE;
197 
198   return EFI_SUCCESS;
199 }
200 
201 /**
202   This function calculates and updates an UINT8 checksum.
203 
204   @param[in]  Buffer          Pointer to buffer to checksum.
205   @param[in]  Size            Number of bytes to checksum.
206 
207 **/
208 VOID
BgrtAcpiTableChecksum(IN UINT8 * Buffer,IN UINTN Size)209 BgrtAcpiTableChecksum (
210   IN UINT8      *Buffer,
211   IN UINTN      Size
212   )
213 {
214   UINTN ChecksumOffset;
215 
216   ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum);
217 
218   //
219   // Set checksum to 0 first.
220   //
221   Buffer[ChecksumOffset] = 0;
222 
223   //
224   // Update checksum value.
225   //
226   Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
227 }
228 
229 /**
230   Allocate EfiBootServicesData below 4G memory address.
231 
232   This function allocates EfiBootServicesData below 4G memory address.
233 
234   @param[in]  Size   Size of memory to allocate.
235 
236   @return Allocated address for output.
237 
238 **/
239 VOID *
BgrtAllocateBsDataMemoryBelow4G(IN UINTN Size)240 BgrtAllocateBsDataMemoryBelow4G (
241   IN UINTN       Size
242   )
243 {
244   UINTN                 Pages;
245   EFI_PHYSICAL_ADDRESS  Address;
246   EFI_STATUS            Status;
247   VOID                  *Buffer;
248 
249   Pages   = EFI_SIZE_TO_PAGES (Size);
250   Address = 0xffffffff;
251 
252   Status = gBS->AllocatePages (
253                   AllocateMaxAddress,
254                   EfiBootServicesData,
255                   Pages,
256                   &Address
257                   );
258   ASSERT_EFI_ERROR (Status);
259 
260   Buffer = (VOID *) (UINTN) Address;
261   ZeroMem (Buffer, Size);
262 
263   return Buffer;
264 }
265 
266 /**
267   Install Boot Graphics Resource Table to ACPI table.
268 
269   @return Status code.
270 
271 **/
272 EFI_STATUS
InstallBootGraphicsResourceTable(VOID)273 InstallBootGraphicsResourceTable (
274   VOID
275   )
276 {
277   EFI_STATUS                    Status;
278   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;
279   UINT8                         *ImageBuffer;
280   UINTN                         PaddingSize;
281   UINTN                         BmpSize;
282   UINTN                         OrigBmpSize;
283   UINT8                         *Image;
284   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
285   UINTN                         Col;
286   UINTN                         Row;
287 
288   //
289   // Get ACPI Table protocol.
290   //
291   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
292   if (EFI_ERROR (Status)) {
293     return Status;
294   }
295 
296   //
297   // Check whether Boot Graphics Resource Table is already installed.
298   //
299   if (mAcpiBgrtInstalled) {
300     if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) {
301       //
302       // Nothing has changed
303       //
304       return EFI_SUCCESS;
305     } else {
306       //
307       // If BGRT data change happens. Uninstall Orignal AcpiTable first
308       //
309       Status = AcpiTableProtocol->UninstallAcpiTable (
310                                     AcpiTableProtocol,
311                                     mBootGraphicsResourceTableKey
312                                     );
313       if (EFI_ERROR (Status)) {
314         return Status;
315       }
316     }
317   } else {
318     //
319     // Check whether Logo exist.
320     //
321     if ( mLogoBltBuffer == NULL) {
322       return EFI_NOT_FOUND;
323     }
324   }
325 
326   if (mAcpiBgrtBufferChanged) {
327     //
328     // reserve original BGRT buffer size
329     //
330     OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER);
331     //
332     // Free orignal BMP memory
333     //
334     if (mBootGraphicsResourceTableTemplate.ImageAddress) {
335       gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES(OrigBmpSize));
336     }
337 
338     //
339     // Allocate memory for BMP file.
340     //
341     PaddingSize = mLogoWidth & 0x3;
342 
343     //
344     // First check mLogoWidth * 3 + PaddingSize doesn't overflow
345     //
346     if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) {
347       return EFI_UNSUPPORTED;
348     }
349 
350     //
351     // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
352     //
353     if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) {
354       return EFI_UNSUPPORTED;
355     }
356 
357     //
358     // The image should be stored in EfiBootServicesData, allowing the system to reclaim the memory
359     //
360     BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER);
361     ImageBuffer = BgrtAllocateBsDataMemoryBelow4G (BmpSize);
362     if (ImageBuffer == NULL) {
363       return EFI_OUT_OF_RESOURCES;
364     }
365 
366     mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
367     mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
368     mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth;
369     mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight;
370     CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
371 
372     //
373     // Convert BLT buffer to BMP file.
374     //
375     Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER);
376     for (Row = 0; Row < mLogoHeight; Row++) {
377     BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth];
378 
379     for (Col = 0; Col < mLogoWidth; Col++) {
380       *Image++ = BltPixel->Blue;
381       *Image++ = BltPixel->Green;
382       *Image++ = BltPixel->Red;
383       BltPixel++;
384     }
385 
386       //
387       // Padding for 4 byte alignment.
388       //
389       Image += PaddingSize;
390     }
391     FreePool (mLogoBltBuffer);
392     mLogoBltBuffer = NULL;
393 
394     mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer;
395     mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX;
396     mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY;
397   }
398 
399   mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID);
400 
401   //
402   // Update Checksum.
403   //
404   BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE));
405 
406   //
407   // Publish Boot Graphics Resource Table.
408   //
409   Status = AcpiTableProtocol->InstallAcpiTable (
410                                 AcpiTableProtocol,
411                                 &mBootGraphicsResourceTableTemplate,
412                                 sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
413                                 &mBootGraphicsResourceTableKey
414                                 );
415   if (EFI_ERROR (Status)) {
416     return Status;
417   }
418 
419   mAcpiBgrtInstalled = TRUE;
420   mAcpiBgrtStatusChanged = FALSE;
421   mAcpiBgrtBufferChanged = FALSE;
422 
423   return Status;
424 }
425 
426 /**
427   Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
428   install the Boot Graphics Resource Table.
429 
430   @param[in]  Event   The Event that is being processed.
431   @param[in]  Context The Event Context.
432 
433 **/
434 VOID
435 EFIAPI
BgrtReadyToBootEventNotify(IN EFI_EVENT Event,IN VOID * Context)436 BgrtReadyToBootEventNotify (
437   IN EFI_EVENT        Event,
438   IN VOID             *Context
439   )
440 {
441   InstallBootGraphicsResourceTable ();
442 }
443 
444 /**
445   The module Entry Point of the Boot Graphics Resource Table DXE driver.
446 
447   @param[in]  ImageHandle    The firmware allocated handle for the EFI image.
448   @param[in]  SystemTable    A pointer to the EFI System Table.
449 
450   @retval EFI_SUCCESS    The entry point is executed successfully.
451   @retval Other          Some error occurs when executing this entry point.
452 
453 **/
454 EFI_STATUS
455 EFIAPI
BootGraphicsDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)456 BootGraphicsDxeEntryPoint (
457   IN EFI_HANDLE          ImageHandle,
458   IN EFI_SYSTEM_TABLE    *SystemTable
459   )
460 {
461   EFI_STATUS  Status;
462   UINT64      OemTableId;
463 
464   CopyMem (
465     mBootGraphicsResourceTableTemplate.Header.OemId,
466     PcdGetPtr (PcdAcpiDefaultOemId),
467     sizeof (mBootGraphicsResourceTableTemplate.Header.OemId)
468     );
469   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
470   CopyMem (&mBootGraphicsResourceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
471   mBootGraphicsResourceTableTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
472   mBootGraphicsResourceTableTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
473   mBootGraphicsResourceTableTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
474 
475   //
476   // Install Boot Logo protocol.
477   //
478   Status = gBS->InstallMultipleProtocolInterfaces (
479                   &mBootLogoHandle,
480                   &gEfiBootLogoProtocolGuid,
481                   &mBootLogoProtocolTemplate,
482                   NULL
483                   );
484   ASSERT_EFI_ERROR (Status);
485 
486   //
487   // Register notify function to install BGRT on ReadyToBoot Event.
488   //
489   Status = gBS->CreateEventEx (
490                   EVT_NOTIFY_SIGNAL,
491                   TPL_CALLBACK,
492                   BgrtReadyToBootEventNotify,
493                   NULL,
494                   &gEfiEventReadyToBootGuid,
495                   &mBootGraphicsReadyToBootEvent
496                   );
497   ASSERT_EFI_ERROR (Status);
498 
499   return Status;
500 }
501