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