2 Provides services to display completion progress of a firmware update on a
3 graphical console that supports the Graphics Output Protocol.
5 Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
6 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1. Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <Library/BaseMemoryLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/UefiBootServicesTableLib.h>
33 #include <Library/DebugLib.h>
34 #include <Library/BaseLib.h>
35 #include <Library/UefiLib.h>
37 #include <Protocol/GraphicsOutput.h>
38 #include <Protocol/BootLogo2.h>
41 // Values in percent of of logo height.
43 #define LOGO_BOTTOM_PADDING 20
44 #define PROGRESS_BLOCK_HEIGHT 10
47 // Graphics Output Protocol instance to display progress bar
49 EFI_GRAPHICS_OUTPUT_PROTOCOL
*mGop
= NULL
;
52 // Set to 100 percent so it is reset on first call.
54 UINTN mPreviousProgress
= 100;
57 // Display coordinates for the progress bar.
63 // Width and height of the progress bar.
65 UINTN mBlockWidth
= 0;
66 UINTN mBlockHeight
= 0;
69 // GOP bitmap of the progress bar. Initialized on every new progress of 100%
71 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*mBlockBitmap
;
74 // GOP bitmap of the progress bar backround. Initialized once.
76 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*mProgressBarBackground
;
79 // Default mask used to detect the left, right , top, and bottom of logo. Only
80 // green and blue pixels are used for logo detection.
82 const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mLogoDetectionColorMask
= {
92 // Background color of progress bar. Grey.
94 const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarBackgroundColor
= {
104 // Default color of progress completion. White.
106 const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarDefaultColor
= {
116 // Set to TRUE if a valid Graphics Output Protocol is found and the progress
117 // bar fits under the boot logo using the current graphics mode.
119 BOOLEAN mGraphicsGood
= FALSE
;
122 Internal function used to find the bounds of the white logo (on black or
125 These bounds are then computed to find the block size, 0%, 100%, etc.
140 UINTN OffsetX
; // Logo screen coordinate
141 UINTN OffsetY
; // Logo screen coordinate
142 UINTN Width
; // Width of logo in pixels
143 UINTN Height
; // Height of logo in pixels
144 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Logo
;
145 EDKII_BOOT_LOGO2_PROTOCOL
*BootLogo
;
146 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*Pixel
;
152 // Return if a Graphics Output Protocol ha snot been found.
155 DEBUG ((DEBUG_ERROR
, "No GOP found. No progress bar support. \n"));
160 // Get boot logo protocol so we know where on the screen to grab
162 Status
= gBS
->LocateProtocol (
163 &gEdkiiBootLogo2ProtocolGuid
,
167 if ((BootLogo
== NULL
) || (EFI_ERROR (Status
))) {
168 DEBUG ((DEBUG_ERROR
, "Failed to locate gEdkiiBootLogo2ProtocolGuid. No Progress bar support. \n", Status
));
173 // Get logo location and size
175 Status
= BootLogo
->GetBootLogo (
183 if (EFI_ERROR (Status
)) {
184 DEBUG ((DEBUG_ERROR
, "Failed to Get Boot Logo Status = %r. No Progress bar support. \n", Status
));
189 // Within logo buffer find where the actual logo starts/ends
195 // Find left side of logo in logo coordinates
197 for (LogoX
= 0, LogoStartX
= Width
; LogoX
< LogoStartX
; LogoX
++) {
198 Pixel
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*)(Logo
+ LogoX
);
199 for (LogoY
= 0; LogoY
< (INTN
)Height
; LogoY
++) {
200 if ((Pixel
->Raw
& mLogoDetectionColorMask
.Raw
) != 0x0) {
203 // For loop searches from right side back to this column.
206 DEBUG ((DEBUG_INFO
, "StartX found at (%d, %d) Color is: 0x%X \n", LogoX
, LogoY
, Pixel
->Raw
));
209 Pixel
= Pixel
+ Width
;
214 // Find right side of logo
216 for (LogoX
= Width
- 1; LogoX
>= LogoEndX
; LogoX
--) {
217 Pixel
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*)(Logo
+ LogoX
);
218 for (LogoY
= 0; LogoY
< (INTN
)Height
; LogoY
++) {
219 if ((Pixel
->Raw
& mLogoDetectionColorMask
.Raw
) != 0x0) {
221 DEBUG ((DEBUG_INFO
, "EndX found at (%d, %d) Color is: 0x%X \n", LogoX
, LogoY
, Pixel
->Raw
));
224 Pixel
= Pixel
+ Width
;
229 // Compute mBlockWidth
231 mBlockWidth
= ((LogoEndX
- LogoStartX
) + 99) / 100;
234 // Adjust mStartX based on block width so it is centered under logo
236 mStartX
= LogoStartX
+ OffsetX
- (((mBlockWidth
* 100) - (LogoEndX
- LogoStartX
)) / 2);
237 DEBUG ((DEBUG_INFO
, "mBlockWidth set to 0x%X\n", mBlockWidth
));
238 DEBUG ((DEBUG_INFO
, "mStartX set to 0x%X\n", mStartX
));
241 // Find the top of the logo
243 for (LogoY
= 0, LogoStartY
= Height
; LogoY
< LogoStartY
; LogoY
++) {
244 Pixel
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*)(Logo
+ (Width
* LogoY
));
245 for (LogoX
= 0; LogoX
< (INTN
)Width
; LogoX
++) {
247 if ((Pixel
->Raw
& mLogoDetectionColorMask
.Raw
) != 0x0) {
249 LogoEndY
= LogoY
; //for next loop will search from bottom side back to this row.
250 DEBUG ((DEBUG_INFO
, "StartY found at (%d, %d) Color is: 0x%X \n", LogoX
, LogoY
, Pixel
->Raw
));
258 // Find the bottom of the logo
260 for (LogoY
= Height
- 1; LogoY
>= LogoEndY
; LogoY
--) {
261 Pixel
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*)(Logo
+ (Width
* LogoY
));
262 for (LogoX
= 0; LogoX
< (INTN
)Width
; LogoX
++) {
263 if ((Pixel
->Raw
& mLogoDetectionColorMask
.Raw
) != 0x0) {
265 DEBUG ((DEBUG_INFO
, "EndY found at (%d, %d) Color is: 0x%X \n", LogoX
, LogoY
, Pixel
->Raw
));
273 // Compute bottom padding (distance between logo bottom and progress bar)
275 mStartY
= (((LogoEndY
- LogoStartY
) * LOGO_BOTTOM_PADDING
) / 100) + LogoEndY
+ OffsetY
;
278 // Compute progress bar height
280 mBlockHeight
= (((LogoEndY
- LogoStartY
) * PROGRESS_BLOCK_HEIGHT
) / 100);
282 DEBUG ((DEBUG_INFO
, "mBlockHeight set to 0x%X\n", mBlockHeight
));
285 // Create progress bar background (one time init).
287 mProgressBarBackground
= AllocatePool (mBlockWidth
* 100 * mBlockHeight
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
288 if (mProgressBarBackground
== NULL
) {
289 DEBUG ((DEBUG_ERROR
, "Failed to allocate progress bar background\n"));
294 // Fill the progress bar with the background color
297 mProgressBarBackground
,
298 (mBlockWidth
* 100 * mBlockHeight
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
)),
299 mProgressBarBackgroundColor
.Raw
303 // Allocate mBlockBitmap
305 mBlockBitmap
= AllocatePool (mBlockWidth
* mBlockHeight
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
306 if (mBlockBitmap
== NULL
) {
307 FreePool (mProgressBarBackground
);
308 DEBUG ((DEBUG_ERROR
, "Failed to allocate block\n"));
313 // Check screen width and height and make sure it fits.
315 if ((mBlockHeight
> Height
) || (mBlockWidth
> Width
) || (mBlockHeight
< 1) || (mBlockWidth
< 1)) {
316 DEBUG ((DEBUG_ERROR
, "DisplayUpdateProgressLib - Progress - Failed to get valid width and height.\n"));
317 DEBUG ((DEBUG_ERROR
, "DisplayUpdateProgressLib - Progress - mBlockHeight: 0x%X mBlockWidth: 0x%X.\n", mBlockHeight
, mBlockWidth
));
318 FreePool (mProgressBarBackground
);
319 FreePool (mBlockBitmap
);
323 mGraphicsGood
= TRUE
;
327 Function indicates the current completion progress of a firmware update.
328 Platform may override with its own specific function.
330 @param[in] Completion A value between 0 and 100 indicating the current
331 completion progress of a firmware update. This
332 value must the the same or higher than previous
333 calls to this service. The first call of 0 or a
334 value of 0 after reaching a value of 100 resets
335 the progress indicator to 0.
336 @param[in] Color Color of the progress indicator. Only used when
337 Completion is 0 to set the color of the progress
338 indicator. If Color is NULL, then the default color
341 @retval EFI_SUCCESS Progress displayed successfully.
342 @retval EFI_INVALID_PARAMETER Completion is not in range 0..100.
343 @retval EFI_INVALID_PARAMETER Completion is less than Completion value from
344 a previous call to this service.
345 @retval EFI_NOT_READY The device used to indicate progress is not
350 DisplayUpdateProgress (
352 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION
*Color OPTIONAL
362 if (Completion
> 100) {
363 return EFI_INVALID_PARAMETER
;
367 // Check to see if this Completion percentage has already been displayed
369 if (Completion
== mPreviousProgress
) {
374 // Find Graphics Output Protocol if not already set. 1 time.
377 Status
= gBS
->HandleProtocol (
378 gST
->ConsoleOutHandle
,
379 &gEfiGraphicsOutputProtocolGuid
,
382 if (EFI_ERROR (Status
)) {
383 Status
= gBS
->LocateProtocol (&gEfiGraphicsOutputProtocolGuid
, NULL
, (VOID
**)&mGop
);
384 if (EFI_ERROR (Status
)) {
386 DEBUG ((DEBUG_ERROR
, "Show Progress Function could not locate GOP. Status = %r\n", Status
));
387 return EFI_NOT_READY
;
398 // Make sure a valid start, end, and size info are available (find the Logo)
400 if (!mGraphicsGood
) {
401 DEBUG ((DEBUG_INFO
, "Graphics Not Good. Not doing any onscreen visual display\n"));
402 return EFI_NOT_READY
;
406 // Do special init on first call of each progress session
408 if (mPreviousProgress
== 100) {
410 // Draw progress bar background
414 mProgressBarBackground
,
425 DEBUG ((DEBUG_VERBOSE
, "Color is 0x%X\n",
426 (Color
== NULL
) ? mProgressBarDefaultColor
.Raw
: Color
->Raw
430 // Update block bitmap with correct color
434 (mBlockWidth
* mBlockHeight
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
)),
435 (Color
== NULL
) ? mProgressBarDefaultColor
.Raw
: Color
->Raw
441 mPreviousProgress
= 0;
445 // Can not update progress bar if Completion is less than previous
447 if (Completion
< mPreviousProgress
) {
448 DEBUG ((DEBUG_WARN
, "WARNING: Completion (%d) should not be lesss than Previous (%d)!!!\n", Completion
, mPreviousProgress
));
449 return EFI_INVALID_PARAMETER
;
452 PreX
= ((mPreviousProgress
* mBlockWidth
) + mStartX
);
453 for (Index
= 0; Index
< (Completion
- mPreviousProgress
); Index
++) {
455 // Show progress by coloring new area
472 mPreviousProgress
= Completion
;