2c1e8ea5b4f2a83bb7f16acfe3c4cacb503ef334
[mirror_edk2.git] / MdeModulePkg / Library / BootLogoLib / BootLogoLib.c
1 /** @file
2 This library is only intended to be used by PlatformBootManagerLib
3 to show progress bar and LOGO.
4
5 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials are licensed and made available under
7 the terms and conditions of the BSD License that accompanies this distribution.
8 The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Uefi.h>
17 #include <Protocol/GraphicsOutput.h>
18 #include <Protocol/SimpleTextOut.h>
19 #include <Protocol/PlatformLogo.h>
20 #include <Protocol/UgaDraw.h>
21 #include <Protocol/BootLogo.h>
22 #include <Library/BaseLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/PcdLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/DebugLib.h>
29
30 /**
31 Show LOGO returned from Edkii Platform Logo protocol on all consoles.
32
33 @retval EFI_SUCCESS Logo was displayed.
34 @retval EFI_UNSUPPORTED Logo was not found or cannot be displayed.
35 **/
36 EFI_STATUS
37 EFIAPI
38 BootLogoEnableLogo (
39 VOID
40 )
41 {
42 EFI_STATUS Status;
43 EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo;
44 EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute;
45 INTN OffsetX;
46 INTN OffsetY;
47 UINT32 SizeOfX;
48 UINT32 SizeOfY;
49 INTN DestX;
50 INTN DestY;
51 UINT32 Instance;
52 EFI_IMAGE_INPUT Image;
53 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
54 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
55 UINT32 ColorDepth;
56 UINT32 RefreshRate;
57 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
58 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
59 UINTN NumberOfLogos;
60 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
61 UINTN LogoDestX;
62 UINTN LogoDestY;
63 UINTN LogoHeight;
64 UINTN LogoWidth;
65 UINTN NewDestX;
66 UINTN NewDestY;
67 UINTN BufferSize;
68
69 Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **) &PlatformLogo);
70 if (EFI_ERROR (Status)) {
71 return EFI_UNSUPPORTED;
72 }
73
74 UgaDraw = NULL;
75 //
76 // Try to open GOP first
77 //
78 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
79 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
80 GraphicsOutput = NULL;
81 //
82 // Open GOP failed, try to open UGA
83 //
84 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
85 if (EFI_ERROR (Status)) {
86 UgaDraw = NULL;
87 }
88 }
89 if (EFI_ERROR (Status)) {
90 return EFI_UNSUPPORTED;
91 }
92
93 //
94 // Try to open Boot Logo Protocol.
95 //
96 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
97 if (EFI_ERROR (Status)) {
98 BootLogo = NULL;
99 }
100
101 //
102 // Erase Cursor from screen
103 //
104 gST->ConOut->EnableCursor (gST->ConOut, FALSE);
105
106 if (GraphicsOutput != NULL) {
107 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
108 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
109
110 } else {
111 ASSERT (UgaDraw != NULL);
112 Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
113 if (EFI_ERROR (Status)) {
114 return EFI_UNSUPPORTED;
115 }
116 }
117
118 Blt = NULL;
119 NumberOfLogos = 0;
120 LogoDestX = 0;
121 LogoDestY = 0;
122 LogoHeight = 0;
123 LogoWidth = 0;
124 NewDestX = 0;
125 NewDestY = 0;
126 Instance = 0;
127 DestX = 0;
128 DestY = 0;
129 while (TRUE) {
130 //
131 // Get image from PlatformLogo protocol.
132 //
133 Status = PlatformLogo->GetImage (
134 PlatformLogo,
135 &Instance,
136 &Image,
137 &Attribute,
138 &OffsetX,
139 &OffsetY
140 );
141 if (EFI_ERROR (Status)) {
142 break;
143 }
144
145 if (EFI_ERROR (Status)) {
146 continue;
147 }
148
149 if (Blt != NULL) {
150 FreePool (Blt);
151 }
152 Blt = Image.Bitmap;
153
154 //
155 // Calculate the display position according to Attribute.
156 //
157 switch (Attribute) {
158 case EdkiiPlatformLogoDisplayAttributeLeftTop:
159 DestX = 0;
160 DestY = 0;
161 break;
162 case EdkiiPlatformLogoDisplayAttributeCenterTop:
163 DestX = (SizeOfX - Image.Width) / 2;
164 DestY = 0;
165 break;
166 case EdkiiPlatformLogoDisplayAttributeRightTop:
167 DestX = SizeOfX - Image.Width;
168 DestY = 0;
169 break;
170
171 case EdkiiPlatformLogoDisplayAttributeCenterLeft:
172 DestX = 0;
173 DestY = (SizeOfY - Image.Height) / 2;
174 break;
175 case EdkiiPlatformLogoDisplayAttributeCenter:
176 DestX = (SizeOfX - Image.Width) / 2;
177 DestY = (SizeOfY - Image.Height) / 2;
178 break;
179 case EdkiiPlatformLogoDisplayAttributeCenterRight:
180 DestX = SizeOfX - Image.Width;
181 DestY = (SizeOfY - Image.Height) / 2;
182 break;
183
184 case EdkiiPlatformLogoDisplayAttributeLeftBottom:
185 DestX = 0;
186 DestY = SizeOfY - Image.Height;
187 break;
188 case EdkiiPlatformLogoDisplayAttributeCenterBottom:
189 DestX = (SizeOfX - Image.Width) / 2;
190 DestY = SizeOfY - Image.Height;
191 break;
192 case EdkiiPlatformLogoDisplayAttributeRightBottom:
193 DestX = SizeOfX - Image.Width;
194 DestY = SizeOfY - Image.Height;
195 break;
196
197 default:
198 ASSERT (FALSE);
199 continue;
200 break;
201 }
202
203 DestX += OffsetX;
204 DestY += OffsetY;
205
206 if ((DestX >= 0) && (DestY >= 0)) {
207 if (GraphicsOutput != NULL) {
208 Status = GraphicsOutput->Blt (
209 GraphicsOutput,
210 Blt,
211 EfiBltBufferToVideo,
212 0,
213 0,
214 (UINTN) DestX,
215 (UINTN) DestY,
216 Image.Width,
217 Image.Height,
218 Image.Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
219 );
220 } else {
221 ASSERT (UgaDraw != NULL);
222 Status = UgaDraw->Blt (
223 UgaDraw,
224 (EFI_UGA_PIXEL *) Blt,
225 EfiUgaBltBufferToVideo,
226 0,
227 0,
228 (UINTN) DestX,
229 (UINTN) DestY,
230 Image.Width,
231 Image.Height,
232 Image.Width * sizeof (EFI_UGA_PIXEL)
233 );
234 }
235
236 //
237 // Report displayed Logo information.
238 //
239 if (!EFI_ERROR (Status)) {
240 NumberOfLogos++;
241
242 if (NumberOfLogos == 1) {
243 //
244 // The first Logo.
245 //
246 LogoDestX = (UINTN) DestX;
247 LogoDestY = (UINTN) DestY;
248 LogoWidth = Image.Width;
249 LogoHeight = Image.Height;
250 } else {
251 //
252 // Merge new logo with old one.
253 //
254 NewDestX = MIN ((UINTN) DestX, LogoDestX);
255 NewDestY = MIN ((UINTN) DestY, LogoDestY);
256 LogoWidth = MAX ((UINTN) DestX + Image.Width, LogoDestX + LogoWidth) - NewDestX;
257 LogoHeight = MAX ((UINTN) DestY + Image.Height, LogoDestY + LogoHeight) - NewDestY;
258
259 LogoDestX = NewDestX;
260 LogoDestY = NewDestY;
261 }
262 }
263 }
264 }
265
266 if (BootLogo == NULL || NumberOfLogos == 0) {
267 //
268 // No logo displayed.
269 //
270 if (Blt != NULL) {
271 FreePool (Blt);
272 }
273
274 return Status;
275 }
276
277 //
278 // Advertise displayed Logo information.
279 //
280 if (NumberOfLogos == 1) {
281 //
282 // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
283 //
284 LogoBlt = Blt;
285 Status = EFI_SUCCESS;
286 } else {
287 //
288 // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
289 //
290 if (Blt != NULL) {
291 FreePool (Blt);
292 }
293
294 //
295 // Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
296 //
297 if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
298 return EFI_UNSUPPORTED;
299 }
300 BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
301
302 LogoBlt = AllocatePool (BufferSize);
303 if (LogoBlt == NULL) {
304 return EFI_OUT_OF_RESOURCES;
305 }
306
307 if (GraphicsOutput != NULL) {
308 Status = GraphicsOutput->Blt (
309 GraphicsOutput,
310 LogoBlt,
311 EfiBltVideoToBltBuffer,
312 LogoDestX,
313 LogoDestY,
314 0,
315 0,
316 LogoWidth,
317 LogoHeight,
318 LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
319 );
320 } else {
321 Status = UgaDraw->Blt (
322 UgaDraw,
323 (EFI_UGA_PIXEL *) LogoBlt,
324 EfiUgaVideoToBltBuffer,
325 LogoDestX,
326 LogoDestY,
327 0,
328 0,
329 LogoWidth,
330 LogoHeight,
331 LogoWidth * sizeof (EFI_UGA_PIXEL)
332 );
333 }
334 }
335
336 if (!EFI_ERROR (Status)) {
337 BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
338 }
339 FreePool (LogoBlt);
340
341 return Status;
342 }
343
344 /**
345 Use SystemTable Conout to turn on video based Simple Text Out consoles. The
346 Simple Text Out screens will now be synced up with all non video output devices
347
348 @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
349
350 **/
351 EFI_STATUS
352 EFIAPI
353 BootLogoDisableLogo (
354 VOID
355 )
356 {
357
358 //
359 // Enable Cursor on Screen
360 //
361 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
362 return EFI_SUCCESS;
363 }
364
365
366 /**
367
368 Update progress bar with title above it. It only works in Graphics mode.
369
370 @param TitleForeground Foreground color for Title.
371 @param TitleBackground Background color for Title.
372 @param Title Title above progress bar.
373 @param ProgressColor Progress bar color.
374 @param Progress Progress (0-100)
375 @param PreviousValue The previous value of the progress.
376
377 @retval EFI_STATUS Success update the progress bar
378
379 **/
380 EFI_STATUS
381 EFIAPI
382 BootLogoUpdateProgress (
383 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
384 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
385 IN CHAR16 *Title,
386 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
387 IN UINTN Progress,
388 IN UINTN PreviousValue
389 )
390 {
391 EFI_STATUS Status;
392 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
393 EFI_UGA_DRAW_PROTOCOL *UgaDraw;
394 UINT32 SizeOfX;
395 UINT32 SizeOfY;
396 UINT32 ColorDepth;
397 UINT32 RefreshRate;
398 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
399 UINTN BlockHeight;
400 UINTN BlockWidth;
401 UINTN BlockNum;
402 UINTN PosX;
403 UINTN PosY;
404 UINTN Index;
405
406 if (Progress > 100) {
407 return EFI_INVALID_PARAMETER;
408 }
409
410 UgaDraw = NULL;
411 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
412 if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
413 GraphicsOutput = NULL;
414
415 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
416 if (EFI_ERROR (Status)) {
417 UgaDraw = NULL;
418 }
419 }
420 if (EFI_ERROR (Status)) {
421 return EFI_UNSUPPORTED;
422 }
423
424 SizeOfX = 0;
425 SizeOfY = 0;
426 if (GraphicsOutput != NULL) {
427 SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
428 SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
429 } else if (UgaDraw != NULL) {
430 Status = UgaDraw->GetMode (
431 UgaDraw,
432 &SizeOfX,
433 &SizeOfY,
434 &ColorDepth,
435 &RefreshRate
436 );
437 if (EFI_ERROR (Status)) {
438 return EFI_UNSUPPORTED;
439 }
440 } else {
441 return EFI_UNSUPPORTED;
442 }
443
444 BlockWidth = SizeOfX / 100;
445 BlockHeight = SizeOfY / 50;
446
447 BlockNum = Progress;
448
449 PosX = 0;
450 PosY = SizeOfY * 48 / 50;
451
452 if (BlockNum == 0) {
453 //
454 // Clear progress area
455 //
456 SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
457
458 if (GraphicsOutput != NULL) {
459 Status = GraphicsOutput->Blt (
460 GraphicsOutput,
461 &Color,
462 EfiBltVideoFill,
463 0,
464 0,
465 0,
466 PosY - EFI_GLYPH_HEIGHT - 1,
467 SizeOfX,
468 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
469 SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
470 );
471 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
472 Status = UgaDraw->Blt (
473 UgaDraw,
474 (EFI_UGA_PIXEL *) &Color,
475 EfiUgaVideoFill,
476 0,
477 0,
478 0,
479 PosY - EFI_GLYPH_HEIGHT - 1,
480 SizeOfX,
481 SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
482 SizeOfX * sizeof (EFI_UGA_PIXEL)
483 );
484 } else {
485 return EFI_UNSUPPORTED;
486 }
487 }
488 //
489 // Show progress by drawing blocks
490 //
491 for (Index = PreviousValue; Index < BlockNum; Index++) {
492 PosX = Index * BlockWidth;
493 if (GraphicsOutput != NULL) {
494 Status = GraphicsOutput->Blt (
495 GraphicsOutput,
496 &ProgressColor,
497 EfiBltVideoFill,
498 0,
499 0,
500 PosX,
501 PosY,
502 BlockWidth - 1,
503 BlockHeight,
504 (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
505 );
506 } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
507 Status = UgaDraw->Blt (
508 UgaDraw,
509 (EFI_UGA_PIXEL *) &ProgressColor,
510 EfiUgaVideoFill,
511 0,
512 0,
513 PosX,
514 PosY,
515 BlockWidth - 1,
516 BlockHeight,
517 (BlockWidth) * sizeof (EFI_UGA_PIXEL)
518 );
519 } else {
520 return EFI_UNSUPPORTED;
521 }
522 }
523
524 PrintXY (
525 (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
526 PosY - EFI_GLYPH_HEIGHT - 1,
527 &TitleForeground,
528 &TitleBackground,
529 Title
530 );
531
532 return EFI_SUCCESS;
533 }