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 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 * 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 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 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 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