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