]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c
MdeModulePkg/BootGraphicsResourceTableDxe: don't allocate below 4 GB
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / BootGraphicsResourceTableDxe / BootGraphicsResourceTableDxe.c
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
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
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 Install Boot Graphics Resource Table to ACPI table.
231
232 @return Status code.
233
234 **/
235 EFI_STATUS
236 InstallBootGraphicsResourceTable (
237 VOID
238 )
239 {
240 EFI_STATUS Status;
241 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
242 UINT8 *ImageBuffer;
243 UINTN PaddingSize;
244 UINTN BmpSize;
245 UINTN OrigBmpSize;
246 UINT8 *Image;
247 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
248 UINTN Col;
249 UINTN Row;
250
251 //
252 // Get ACPI Table protocol.
253 //
254 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
255 if (EFI_ERROR (Status)) {
256 return Status;
257 }
258
259 //
260 // Check whether Boot Graphics Resource Table is already installed.
261 //
262 if (mAcpiBgrtInstalled) {
263 if (!mAcpiBgrtStatusChanged && !mAcpiBgrtBufferChanged) {
264 //
265 // Nothing has changed
266 //
267 return EFI_SUCCESS;
268 } else {
269 //
270 // If BGRT data change happens. Uninstall Orignal AcpiTable first
271 //
272 Status = AcpiTableProtocol->UninstallAcpiTable (
273 AcpiTableProtocol,
274 mBootGraphicsResourceTableKey
275 );
276 if (EFI_ERROR (Status)) {
277 return Status;
278 }
279 }
280 } else {
281 //
282 // Check whether Logo exist.
283 //
284 if ( mLogoBltBuffer == NULL) {
285 return EFI_NOT_FOUND;
286 }
287 }
288
289 if (mAcpiBgrtBufferChanged) {
290 //
291 // reserve original BGRT buffer size
292 //
293 OrigBmpSize = mBmpImageHeaderTemplate.ImageSize + sizeof (BMP_IMAGE_HEADER);
294 //
295 // Free orignal BMP memory
296 //
297 if (mBootGraphicsResourceTableTemplate.ImageAddress) {
298 gBS->FreePages(mBootGraphicsResourceTableTemplate.ImageAddress, EFI_SIZE_TO_PAGES(OrigBmpSize));
299 }
300
301 //
302 // Allocate memory for BMP file.
303 //
304 PaddingSize = mLogoWidth & 0x3;
305
306 //
307 // First check mLogoWidth * 3 + PaddingSize doesn't overflow
308 //
309 if (mLogoWidth > (((UINT32) ~0) - PaddingSize) / 3 ) {
310 return EFI_UNSUPPORTED;
311 }
312
313 //
314 // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
315 //
316 if (mLogoHeight > (((UINT32) ~0) - sizeof (BMP_IMAGE_HEADER)) / (mLogoWidth * 3 + PaddingSize)) {
317 return EFI_UNSUPPORTED;
318 }
319
320 //
321 // The image should be stored in EfiBootServicesData, allowing the system to reclaim the memory
322 //
323 BmpSize = (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER);
324 ImageBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BmpSize));
325 if (ImageBuffer == NULL) {
326 return EFI_OUT_OF_RESOURCES;
327 }
328
329 ZeroMem (ImageBuffer, BmpSize);
330
331 mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
332 mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
333 mBmpImageHeaderTemplate.PixelWidth = (UINT32) mLogoWidth;
334 mBmpImageHeaderTemplate.PixelHeight = (UINT32) mLogoHeight;
335 CopyMem (ImageBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
336
337 //
338 // Convert BLT buffer to BMP file.
339 //
340 Image = ImageBuffer + sizeof (BMP_IMAGE_HEADER);
341 for (Row = 0; Row < mLogoHeight; Row++) {
342 BltPixel = &mLogoBltBuffer[(mLogoHeight - Row - 1) * mLogoWidth];
343
344 for (Col = 0; Col < mLogoWidth; Col++) {
345 *Image++ = BltPixel->Blue;
346 *Image++ = BltPixel->Green;
347 *Image++ = BltPixel->Red;
348 BltPixel++;
349 }
350
351 //
352 // Padding for 4 byte alignment.
353 //
354 Image += PaddingSize;
355 }
356 FreePool (mLogoBltBuffer);
357 mLogoBltBuffer = NULL;
358
359 mBootGraphicsResourceTableTemplate.ImageAddress = (UINT64) (UINTN) ImageBuffer;
360 mBootGraphicsResourceTableTemplate.ImageOffsetX = (UINT32) mLogoDestX;
361 mBootGraphicsResourceTableTemplate.ImageOffsetY = (UINT32) mLogoDestY;
362 }
363
364 mBootGraphicsResourceTableTemplate.Status = (UINT8) (mIsLogoValid ? EFI_ACPI_5_0_BGRT_STATUS_VALID : EFI_ACPI_5_0_BGRT_STATUS_INVALID);
365
366 //
367 // Update Checksum.
368 //
369 BgrtAcpiTableChecksum ((UINT8 *) &mBootGraphicsResourceTableTemplate, sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE));
370
371 //
372 // Publish Boot Graphics Resource Table.
373 //
374 Status = AcpiTableProtocol->InstallAcpiTable (
375 AcpiTableProtocol,
376 &mBootGraphicsResourceTableTemplate,
377 sizeof (EFI_ACPI_5_0_BOOT_GRAPHICS_RESOURCE_TABLE),
378 &mBootGraphicsResourceTableKey
379 );
380 if (EFI_ERROR (Status)) {
381 return Status;
382 }
383
384 mAcpiBgrtInstalled = TRUE;
385 mAcpiBgrtStatusChanged = FALSE;
386 mAcpiBgrtBufferChanged = FALSE;
387
388 return Status;
389 }
390
391 /**
392 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
393 install the Boot Graphics Resource Table.
394
395 @param[in] Event The Event that is being processed.
396 @param[in] Context The Event Context.
397
398 **/
399 VOID
400 EFIAPI
401 BgrtReadyToBootEventNotify (
402 IN EFI_EVENT Event,
403 IN VOID *Context
404 )
405 {
406 InstallBootGraphicsResourceTable ();
407 }
408
409 /**
410 The module Entry Point of the Boot Graphics Resource Table DXE driver.
411
412 @param[in] ImageHandle The firmware allocated handle for the EFI image.
413 @param[in] SystemTable A pointer to the EFI System Table.
414
415 @retval EFI_SUCCESS The entry point is executed successfully.
416 @retval Other Some error occurs when executing this entry point.
417
418 **/
419 EFI_STATUS
420 EFIAPI
421 BootGraphicsDxeEntryPoint (
422 IN EFI_HANDLE ImageHandle,
423 IN EFI_SYSTEM_TABLE *SystemTable
424 )
425 {
426 EFI_STATUS Status;
427 UINT64 OemTableId;
428
429 CopyMem (
430 mBootGraphicsResourceTableTemplate.Header.OemId,
431 PcdGetPtr (PcdAcpiDefaultOemId),
432 sizeof (mBootGraphicsResourceTableTemplate.Header.OemId)
433 );
434 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
435 CopyMem (&mBootGraphicsResourceTableTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
436 mBootGraphicsResourceTableTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
437 mBootGraphicsResourceTableTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
438 mBootGraphicsResourceTableTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
439
440 //
441 // Install Boot Logo protocol.
442 //
443 Status = gBS->InstallMultipleProtocolInterfaces (
444 &mBootLogoHandle,
445 &gEfiBootLogoProtocolGuid,
446 &mBootLogoProtocolTemplate,
447 NULL
448 );
449 ASSERT_EFI_ERROR (Status);
450
451 //
452 // Register notify function to install BGRT on ReadyToBoot Event.
453 //
454 Status = gBS->CreateEventEx (
455 EVT_NOTIFY_SIGNAL,
456 TPL_CALLBACK,
457 BgrtReadyToBootEventNotify,
458 NULL,
459 &gEfiEventReadyToBootGuid,
460 &mBootGraphicsReadyToBootEvent
461 );
462 ASSERT_EFI_ERROR (Status);
463
464 return Status;
465 }