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