]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformDxe/Platform.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / PlatformDxe / Platform.c
1 /** @file
2 This driver effectuates OVMF's platform configuration settings and exposes
3 them via HII.
4
5 Copyright (C) 2014, Red Hat, Inc.
6 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9 **/
10
11 #include <Library/BaseLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/DevicePathLib.h>
15 #include <Library/HiiLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PrintLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/UefiHiiServicesLib.h>
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/GraphicsOutput.h>
22 #include <Protocol/HiiConfigAccess.h>
23 #include <Guid/MdeModuleHii.h>
24 #include <Guid/OvmfPlatformConfig.h>
25
26 #include "Platform.h"
27 #include "PlatformConfig.h"
28
29 //
30 // The HiiAddPackages() library function requires that any controller (or
31 // image) handle, to be associated with the HII packages under installation, be
32 // "decorated" with a device path. The tradition seems to be a vendor device
33 // path.
34 //
35 // We'd like to associate our HII packages with the driver's image handle. The
36 // first idea is to use the driver image's device path. Unfortunately, loaded
37 // images only come with an EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL (not the
38 // usual EFI_DEVICE_PATH_PROTOCOL), ie. a different GUID. In addition, even the
39 // EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL interface may be NULL, if the image
40 // has been loaded from an "unnamed" memory source buffer.
41 //
42 // Hence let's just stick with the tradition -- use a dedicated vendor device
43 // path, with the driver's FILE_GUID.
44 //
45 #pragma pack(1)
46 typedef struct {
47 VENDOR_DEVICE_PATH VendorDevicePath;
48 EFI_DEVICE_PATH_PROTOCOL End;
49 } PKG_DEVICE_PATH;
50 #pragma pack()
51
52 STATIC PKG_DEVICE_PATH mPkgDevicePath = {
53 {
54 {
55 HARDWARE_DEVICE_PATH,
56 HW_VENDOR_DP,
57 {
58 (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
59 (UINT8)(sizeof (VENDOR_DEVICE_PATH) >> 8)
60 }
61 },
62 EFI_CALLER_ID_GUID
63 },
64 {
65 END_DEVICE_PATH_TYPE,
66 END_ENTIRE_DEVICE_PATH_SUBTYPE,
67 {
68 (UINT8)(END_DEVICE_PATH_LENGTH),
69 (UINT8)(END_DEVICE_PATH_LENGTH >> 8)
70 }
71 }
72 };
73
74 //
75 // The configuration interface between the HII engine (form display etc) and
76 // this driver.
77 //
78 STATIC EFI_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess;
79
80 //
81 // The handle representing our list of packages after installation.
82 //
83 STATIC EFI_HII_HANDLE mInstalledPackages;
84
85 //
86 // The arrays below constitute our HII package list. They are auto-generated by
87 // the VFR compiler and linked into the driver image during the build.
88 //
89 // - The strings package receives its C identifier from the driver's BASE_NAME,
90 // plus "Strings".
91 //
92 // - The forms package receives its C identifier from the VFR file's basename,
93 // plus "Bin".
94 //
95 //
96 extern UINT8 PlatformDxeStrings[];
97 extern UINT8 PlatformFormsBin[];
98
99 //
100 // We want to be notified about GOP installations until we find one GOP
101 // interface that lets us populate the form.
102 //
103 STATIC EFI_EVENT mGopEvent;
104
105 //
106 // The registration record underneath this pointer allows us to iterate through
107 // the GOP instances one by one.
108 //
109 STATIC VOID *mGopTracker;
110
111 //
112 // Cache the resolutions we get from the GOP.
113 //
114 typedef struct {
115 UINT32 X;
116 UINT32 Y;
117 } GOP_MODE;
118
119 STATIC UINTN mNumGopModes;
120 STATIC GOP_MODE *mGopModes;
121
122 /**
123 Load the persistent platform configuration and translate it to binary form
124 state.
125
126 If the platform configuration is missing, then the function fills in a
127 default state.
128
129 @param[out] MainFormState Binary form/widget state after translation.
130
131 @retval EFI_SUCCESS Form/widget state ready.
132 @return Error codes from underlying functions.
133 **/
134 STATIC
135 EFI_STATUS
136 EFIAPI
137 PlatformConfigToFormState (
138 OUT MAIN_FORM_STATE *MainFormState
139 )
140 {
141 EFI_STATUS Status;
142 PLATFORM_CONFIG PlatformConfig;
143 UINT64 OptionalElements;
144 UINTN ModeNumber;
145
146 ZeroMem (MainFormState, sizeof *MainFormState);
147
148 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
149 switch (Status) {
150 case EFI_SUCCESS:
151 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
152 //
153 // Format the preferred resolution as text.
154 //
155 UnicodeSPrintAsciiFormat (
156 (CHAR16 *)MainFormState->CurrentPreferredResolution,
157 sizeof MainFormState->CurrentPreferredResolution,
158 "%Ldx%Ld",
159 (INT64)PlatformConfig.HorizontalResolution,
160 (INT64)PlatformConfig.VerticalResolution
161 );
162
163 //
164 // Try to locate it in the drop-down list too. This may not succeed, but
165 // that's fine.
166 //
167 for (ModeNumber = 0; ModeNumber < mNumGopModes; ++ModeNumber) {
168 if ((mGopModes[ModeNumber].X == PlatformConfig.HorizontalResolution) &&
169 (mGopModes[ModeNumber].Y == PlatformConfig.VerticalResolution))
170 {
171 MainFormState->NextPreferredResolution = (UINT32)ModeNumber;
172 break;
173 }
174 }
175
176 break;
177 }
178
179 //
180 // fall through otherwise
181 //
182
183 case EFI_NOT_FOUND:
184 UnicodeSPrintAsciiFormat (
185 (CHAR16 *)MainFormState->CurrentPreferredResolution,
186 sizeof MainFormState->CurrentPreferredResolution,
187 "Unset"
188 );
189 break;
190
191 default:
192 return Status;
193 }
194
195 return EFI_SUCCESS;
196 }
197
198 /**
199 This function is called by the HII machinery when it fetches the form state.
200
201 See the precise documentation in the UEFI spec.
202
203 @param[in] This The Config Access Protocol instance.
204
205 @param[in] Request A <ConfigRequest> format UCS-2 string describing the
206 query.
207
208 @param[out] Progress A pointer into Request on output, identifying the query
209 element where processing failed.
210
211 @param[out] Results A <MultiConfigAltResp> format UCS-2 string that has
212 all values filled in for the names in the Request
213 string.
214
215 @retval EFI_SUCCESS Extraction of form state in <MultiConfigAltResp>
216 encoding successful.
217 @return Status codes from underlying functions.
218
219 **/
220 STATIC
221 EFI_STATUS
222 EFIAPI
223 ExtractConfig (
224 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
225 IN CONST EFI_STRING Request,
226 OUT EFI_STRING *Progress,
227 OUT EFI_STRING *Results
228 )
229 {
230 MAIN_FORM_STATE MainFormState;
231 EFI_STATUS Status;
232
233 DEBUG ((DEBUG_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));
234
235 Status = PlatformConfigToFormState (&MainFormState);
236 if (EFI_ERROR (Status)) {
237 *Progress = Request;
238 return Status;
239 }
240
241 //
242 // Answer the textual request keying off the binary form state.
243 //
244 Status = gHiiConfigRouting->BlockToConfig (
245 gHiiConfigRouting,
246 Request,
247 (VOID *)&MainFormState,
248 sizeof MainFormState,
249 Results,
250 Progress
251 );
252 if (EFI_ERROR (Status)) {
253 DEBUG ((
254 DEBUG_ERROR,
255 "%a: BlockToConfig(): %r, Progress=\"%s\"\n",
256 __FUNCTION__,
257 Status,
258 (Status == EFI_DEVICE_ERROR) ? NULL : *Progress
259 ));
260 } else {
261 DEBUG ((DEBUG_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));
262 }
263
264 return Status;
265 }
266
267 /**
268 Interpret the binary form state and save it as persistent platform
269 configuration.
270
271 @param[in] MainFormState Binary form/widget state to verify and save.
272
273 @retval EFI_SUCCESS Platform configuration saved.
274 @return Error codes from underlying functions.
275 **/
276 STATIC
277 EFI_STATUS
278 EFIAPI
279 FormStateToPlatformConfig (
280 IN CONST MAIN_FORM_STATE *MainFormState
281 )
282 {
283 EFI_STATUS Status;
284 PLATFORM_CONFIG PlatformConfig;
285 CONST GOP_MODE *GopMode;
286
287 //
288 // There's nothing to do with the textual CurrentPreferredResolution field.
289 // We verify and translate the selection in the drop-down list.
290 //
291 if (MainFormState->NextPreferredResolution >= mNumGopModes) {
292 return EFI_INVALID_PARAMETER;
293 }
294
295 GopMode = mGopModes + MainFormState->NextPreferredResolution;
296
297 ZeroMem (&PlatformConfig, sizeof PlatformConfig);
298 PlatformConfig.HorizontalResolution = GopMode->X;
299 PlatformConfig.VerticalResolution = GopMode->Y;
300
301 Status = PlatformConfigSave (&PlatformConfig);
302 return Status;
303 }
304
305 /**
306 This function is called by the HII machinery when it wants the driver to
307 interpret and persist the form state.
308
309 See the precise documentation in the UEFI spec.
310
311 @param[in] This The Config Access Protocol instance.
312
313 @param[in] Configuration A <ConfigResp> format UCS-2 string describing the
314 form state.
315
316 @param[out] Progress A pointer into Configuration on output,
317 identifying the element where processing failed.
318
319 @retval EFI_SUCCESS Configuration verified, state permanent.
320
321 @return Status codes from underlying functions.
322 **/
323 STATIC
324 EFI_STATUS
325 EFIAPI
326 RouteConfig (
327 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
328 IN CONST EFI_STRING Configuration,
329 OUT EFI_STRING *Progress
330 )
331 {
332 MAIN_FORM_STATE MainFormState;
333 UINTN BlockSize;
334 EFI_STATUS Status;
335
336 DEBUG ((
337 DEBUG_VERBOSE,
338 "%a: Configuration=\"%s\"\n",
339 __FUNCTION__,
340 Configuration
341 ));
342
343 //
344 // the "read" step in RMW
345 //
346 Status = PlatformConfigToFormState (&MainFormState);
347 if (EFI_ERROR (Status)) {
348 *Progress = Configuration;
349 return Status;
350 }
351
352 //
353 // the "modify" step in RMW
354 //
355 // (Update the binary form state. This update may be partial, which is why in
356 // general we must pre-load the form state from the platform config.)
357 //
358 BlockSize = sizeof MainFormState;
359 Status = gHiiConfigRouting->ConfigToBlock (
360 gHiiConfigRouting,
361 Configuration,
362 (VOID *)&MainFormState,
363 &BlockSize,
364 Progress
365 );
366 if (EFI_ERROR (Status)) {
367 DEBUG ((
368 DEBUG_ERROR,
369 "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",
370 __FUNCTION__,
371 Status,
372 (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress
373 ));
374 return Status;
375 }
376
377 //
378 // the "write" step in RMW
379 //
380 Status = FormStateToPlatformConfig (&MainFormState);
381 if (EFI_ERROR (Status)) {
382 *Progress = Configuration;
383 }
384
385 return Status;
386 }
387
388 STATIC
389 EFI_STATUS
390 EFIAPI
391 Callback (
392 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
393 IN EFI_BROWSER_ACTION Action,
394 IN EFI_QUESTION_ID QuestionId,
395 IN UINT8 Type,
396 IN OUT EFI_IFR_TYPE_VALUE *Value,
397 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
398 )
399 {
400 DEBUG ((
401 DEBUG_VERBOSE,
402 "%a: Action=0x%Lx QuestionId=%d Type=%d\n",
403 __FUNCTION__,
404 (UINT64)Action,
405 QuestionId,
406 Type
407 ));
408
409 if (Action != EFI_BROWSER_ACTION_CHANGED) {
410 return EFI_UNSUPPORTED;
411 }
412
413 switch (QuestionId) {
414 case QUESTION_SAVE_EXIT:
415 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
416 break;
417
418 case QUESTION_DISCARD_EXIT:
419 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
420 break;
421
422 default:
423 break;
424 }
425
426 return EFI_SUCCESS;
427 }
428
429 /**
430 Query and save all resolutions supported by the GOP.
431
432 @param[in] Gop The Graphics Output Protocol instance to query.
433
434 @param[out] NumGopModes The number of modes supported by the GOP. On output,
435 this parameter will be positive.
436
437 @param[out] GopModes On output, a dynamically allocated array containing
438 the resolutions returned by the GOP. The caller is
439 responsible for freeing the array after use.
440
441 @retval EFI_UNSUPPORTED No modes found.
442 @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes.
443 @return Error codes from Gop->QueryMode().
444
445 **/
446 STATIC
447 EFI_STATUS
448 EFIAPI
449 QueryGopModes (
450 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
451 OUT UINTN *NumGopModes,
452 OUT GOP_MODE **GopModes
453 )
454 {
455 EFI_STATUS Status;
456 UINT32 ModeNumber;
457
458 if (Gop->Mode->MaxMode == 0) {
459 return EFI_UNSUPPORTED;
460 }
461
462 *NumGopModes = Gop->Mode->MaxMode;
463
464 *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);
465 if (*GopModes == NULL) {
466 return EFI_OUT_OF_RESOURCES;
467 }
468
469 for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {
470 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
471 UINTN SizeOfInfo;
472
473 Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);
474 if (EFI_ERROR (Status)) {
475 goto FreeGopModes;
476 }
477
478 (*GopModes)[ModeNumber].X = Info->HorizontalResolution;
479 (*GopModes)[ModeNumber].Y = Info->VerticalResolution;
480 FreePool (Info);
481 }
482
483 return EFI_SUCCESS;
484
485 FreeGopModes:
486 FreePool (*GopModes);
487
488 return Status;
489 }
490
491 /**
492 Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
493 based on available GOP resolutions, to be placed under a "one-of-many" (ie.
494 "drop down list") opcode.
495
496 @param[in] PackageList The package list with the formset and form for
497 which the drop down options are produced. Option
498 names are added as new strings to PackageList.
499
500 @param[out] OpCodeBuffer On output, a dynamically allocated opcode buffer
501 with drop down list options corresponding to GOP
502 resolutions. The caller is responsible for freeing
503 OpCodeBuffer with HiiFreeOpCodeHandle() after use.
504
505 @param[in] NumGopModes Number of entries in GopModes.
506
507 @param[in] GopModes Array of resolutions retrieved from the GOP.
508
509 @retval EFI_SUCESS Opcodes have been successfully produced.
510
511 @return Status codes from underlying functions. PackageList may
512 have been extended with new strings. OpCodeBuffer is
513 unchanged.
514 **/
515 STATIC
516 EFI_STATUS
517 EFIAPI
518 CreateResolutionOptions (
519 IN EFI_HII_HANDLE PackageList,
520 OUT VOID **OpCodeBuffer,
521 IN UINTN NumGopModes,
522 IN GOP_MODE *GopModes
523 )
524 {
525 EFI_STATUS Status;
526 VOID *OutputBuffer;
527 UINTN ModeNumber;
528
529 OutputBuffer = HiiAllocateOpCodeHandle ();
530 if (OutputBuffer == NULL) {
531 return EFI_OUT_OF_RESOURCES;
532 }
533
534 for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {
535 CHAR16 Desc[MAXSIZE_RES_CUR];
536 EFI_STRING_ID NewString;
537 VOID *OpCode;
538
539 UnicodeSPrintAsciiFormat (
540 Desc,
541 sizeof Desc,
542 "%Ldx%Ld",
543 (INT64)GopModes[ModeNumber].X,
544 (INT64)GopModes[ModeNumber].Y
545 );
546 NewString = HiiSetString (
547 PackageList,
548 0 /* new string */,
549 Desc,
550 NULL /* for all languages */
551 );
552 if (NewString == 0) {
553 Status = EFI_OUT_OF_RESOURCES;
554 goto FreeOutputBuffer;
555 }
556
557 OpCode = HiiCreateOneOfOptionOpCode (
558 OutputBuffer,
559 NewString,
560 0 /* Flags */,
561 EFI_IFR_NUMERIC_SIZE_4,
562 ModeNumber
563 );
564 if (OpCode == NULL) {
565 Status = EFI_OUT_OF_RESOURCES;
566 goto FreeOutputBuffer;
567 }
568 }
569
570 *OpCodeBuffer = OutputBuffer;
571 return EFI_SUCCESS;
572
573 FreeOutputBuffer:
574 HiiFreeOpCodeHandle (OutputBuffer);
575
576 return Status;
577 }
578
579 /**
580 Populate the form identified by the (PackageList, FormSetGuid, FormId)
581 triplet.
582
583 The drop down list of video resolutions is generated from (NumGopModes,
584 GopModes).
585
586 @retval EFI_SUCESS Form successfully updated.
587 @return Status codes from underlying functions.
588
589 **/
590 STATIC
591 EFI_STATUS
592 EFIAPI
593 PopulateForm (
594 IN EFI_HII_HANDLE PackageList,
595 IN EFI_GUID *FormSetGuid,
596 IN EFI_FORM_ID FormId,
597 IN UINTN NumGopModes,
598 IN GOP_MODE *GopModes
599 )
600 {
601 EFI_STATUS Status;
602 VOID *OpCodeBuffer;
603 VOID *OpCode;
604 EFI_IFR_GUID_LABEL *Anchor;
605 VOID *OpCodeBuffer2;
606
607 OpCodeBuffer2 = NULL;
608
609 //
610 // 1. Allocate an empty opcode buffer.
611 //
612 OpCodeBuffer = HiiAllocateOpCodeHandle ();
613 if (OpCodeBuffer == NULL) {
614 return EFI_OUT_OF_RESOURCES;
615 }
616
617 //
618 // 2. Create a label opcode (which is a Tiano extension) inside the buffer.
619 // The label's number must match the "anchor" label in the form.
620 //
621 OpCode = HiiCreateGuidOpCode (
622 OpCodeBuffer,
623 &gEfiIfrTianoGuid,
624 NULL /* optional copy origin */,
625 sizeof *Anchor
626 );
627 if (OpCode == NULL) {
628 Status = EFI_OUT_OF_RESOURCES;
629 goto FreeOpCodeBuffer;
630 }
631
632 Anchor = OpCode;
633 Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
634 Anchor->Number = LABEL_RES_NEXT;
635
636 //
637 // 3. Create the opcodes inside the buffer that are to be inserted into the
638 // form.
639 //
640 // 3.1. Get a list of resolutions.
641 //
642 Status = CreateResolutionOptions (
643 PackageList,
644 &OpCodeBuffer2,
645 NumGopModes,
646 GopModes
647 );
648 if (EFI_ERROR (Status)) {
649 goto FreeOpCodeBuffer;
650 }
651
652 //
653 // 3.2. Create a one-of-many question with the above options.
654 //
655 OpCode = HiiCreateOneOfOpCode (
656 OpCodeBuffer, // create opcode inside this
657 // opcode buffer,
658 QUESTION_RES_NEXT, // ID of question,
659 FORMSTATEID_MAIN_FORM, // identifies form state
660 // storage,
661 (UINT16)OFFSET_OF (
662 MAIN_FORM_STATE, // value of question stored
663 NextPreferredResolution
664 ), // at this offset,
665 STRING_TOKEN (STR_RES_NEXT), // Prompt,
666 STRING_TOKEN (STR_RES_NEXT_HELP), // Help,
667 0, // QuestionFlags,
668 EFI_IFR_NUMERIC_SIZE_4, // see sizeof
669 // NextPreferredResolution,
670 OpCodeBuffer2, // buffer with possible
671 // choices,
672 NULL // DEFAULT opcodes
673 );
674 if (OpCode == NULL) {
675 Status = EFI_OUT_OF_RESOURCES;
676 goto FreeOpCodeBuffer2;
677 }
678
679 //
680 // 4. Update the form with the opcode buffer.
681 //
682 Status = HiiUpdateForm (
683 PackageList,
684 FormSetGuid,
685 FormId,
686 OpCodeBuffer, // buffer with head anchor, and new contents to be
687 // inserted at it
688 NULL // buffer with tail anchor, for deleting old
689 // contents up to it
690 );
691
692 FreeOpCodeBuffer2:
693 HiiFreeOpCodeHandle (OpCodeBuffer2);
694
695 FreeOpCodeBuffer:
696 HiiFreeOpCodeHandle (OpCodeBuffer);
697
698 return Status;
699 }
700
701 /**
702 Load and execute the platform configuration.
703
704 @retval EFI_SUCCESS Configuration loaded and executed.
705 @return Status codes from PlatformConfigLoad().
706 **/
707 STATIC
708 EFI_STATUS
709 EFIAPI
710 ExecutePlatformConfig (
711 VOID
712 )
713 {
714 EFI_STATUS Status;
715 PLATFORM_CONFIG PlatformConfig;
716 UINT64 OptionalElements;
717 RETURN_STATUS PcdStatus;
718
719 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
720 if (EFI_ERROR (Status)) {
721 DEBUG ((
722 (Status == EFI_NOT_FOUND) ? DEBUG_VERBOSE : DEBUG_ERROR,
723 "%a: failed to load platform config: %r\n",
724 __FUNCTION__,
725 Status
726 ));
727 return Status;
728 }
729
730 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
731 //
732 // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
733 //
734 PcdStatus = PcdSet32S (
735 PcdVideoHorizontalResolution,
736 PlatformConfig.HorizontalResolution
737 );
738 ASSERT_RETURN_ERROR (PcdStatus);
739
740 PcdStatus = PcdSet32S (
741 PcdVideoVerticalResolution,
742 PlatformConfig.VerticalResolution
743 );
744 ASSERT_RETURN_ERROR (PcdStatus);
745 }
746
747 return EFI_SUCCESS;
748 }
749
750 /**
751 Notification callback for GOP interface installation.
752
753 @param[in] Event Event whose notification function is being invoked.
754
755 @param[in] Context The pointer to the notification function's context, which
756 is implementation-dependent.
757 **/
758 STATIC
759 VOID
760 EFIAPI
761 GopInstalled (
762 IN EFI_EVENT Event,
763 IN VOID *Context
764 )
765 {
766 EFI_STATUS Status;
767 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
768
769 ASSERT (Event == mGopEvent);
770
771 //
772 // Check further GOPs.
773 //
774 for ( ; ;) {
775 mNumGopModes = 0;
776 mGopModes = NULL;
777
778 Status = gBS->LocateProtocol (
779 &gEfiGraphicsOutputProtocolGuid,
780 mGopTracker,
781 (VOID **)&Gop
782 );
783 if (EFI_ERROR (Status)) {
784 return;
785 }
786
787 Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);
788 if (EFI_ERROR (Status)) {
789 continue;
790 }
791
792 Status = PopulateForm (
793 mInstalledPackages,
794 &gOvmfPlatformConfigGuid,
795 FORMID_MAIN_FORM,
796 mNumGopModes,
797 mGopModes
798 );
799 if (EFI_ERROR (Status)) {
800 FreePool (mGopModes);
801 continue;
802 }
803
804 break;
805 }
806
807 //
808 // Success -- so uninstall this callback. Closing the event removes all
809 // pending notifications and all protocol registrations.
810 //
811 Status = gBS->CloseEvent (mGopEvent);
812 ASSERT_EFI_ERROR (Status);
813 mGopEvent = NULL;
814 mGopTracker = NULL;
815 }
816
817 /**
818 Entry point for this driver.
819
820 @param[in] ImageHandle Image handle of this driver.
821 @param[in] SystemTable Pointer to SystemTable.
822
823 @retval EFI_SUCESS Driver has loaded successfully.
824 @retval EFI_OUT_OF_RESOURCES Failed to install HII packages.
825 @return Error codes from lower level functions.
826
827 **/
828 EFI_STATUS
829 EFIAPI
830 PlatformInit (
831 IN EFI_HANDLE ImageHandle,
832 IN EFI_SYSTEM_TABLE *SystemTable
833 )
834 {
835 EFI_STATUS Status;
836
837 ExecutePlatformConfig ();
838
839 mConfigAccess.ExtractConfig = &ExtractConfig;
840 mConfigAccess.RouteConfig = &RouteConfig;
841 mConfigAccess.Callback = &Callback;
842
843 //
844 // Declare ourselves suitable for HII communication.
845 //
846 Status = gBS->InstallMultipleProtocolInterfaces (
847 &ImageHandle,
848 &gEfiDevicePathProtocolGuid,
849 &mPkgDevicePath,
850 &gEfiHiiConfigAccessProtocolGuid,
851 &mConfigAccess,
852 NULL
853 );
854 if (EFI_ERROR (Status)) {
855 return Status;
856 }
857
858 //
859 // Publish the HII package list to HII Database.
860 //
861 mInstalledPackages = HiiAddPackages (
862 &gEfiCallerIdGuid, // PackageListGuid
863 ImageHandle, // associated DeviceHandle
864 PlatformDxeStrings, // 1st package
865 PlatformFormsBin, // 2nd package
866 NULL // terminator
867 );
868 if (mInstalledPackages == NULL) {
869 Status = EFI_OUT_OF_RESOURCES;
870 goto UninstallProtocols;
871 }
872
873 Status = gBS->CreateEvent (
874 EVT_NOTIFY_SIGNAL,
875 TPL_CALLBACK,
876 &GopInstalled,
877 NULL /* Context */,
878 &mGopEvent
879 );
880 if (EFI_ERROR (Status)) {
881 goto RemovePackages;
882 }
883
884 Status = gBS->RegisterProtocolNotify (
885 &gEfiGraphicsOutputProtocolGuid,
886 mGopEvent,
887 &mGopTracker
888 );
889 if (EFI_ERROR (Status)) {
890 goto CloseGopEvent;
891 }
892
893 //
894 // Check already installed GOPs.
895 //
896 Status = gBS->SignalEvent (mGopEvent);
897 ASSERT_EFI_ERROR (Status);
898
899 return EFI_SUCCESS;
900
901 CloseGopEvent:
902 gBS->CloseEvent (mGopEvent);
903
904 RemovePackages:
905 HiiRemovePackages (mInstalledPackages);
906
907 UninstallProtocols:
908 gBS->UninstallMultipleProtocolInterfaces (
909 ImageHandle,
910 &gEfiDevicePathProtocolGuid,
911 &mPkgDevicePath,
912 &gEfiHiiConfigAccessProtocolGuid,
913 &mConfigAccess,
914 NULL
915 );
916 return Status;
917 }
918
919 /**
920 Unload the driver.
921
922 @param[in] ImageHandle Handle that identifies the image to evict.
923
924 @retval EFI_SUCCESS The image has been unloaded.
925 **/
926 EFI_STATUS
927 EFIAPI
928 PlatformUnload (
929 IN EFI_HANDLE ImageHandle
930 )
931 {
932 if (mGopEvent == NULL) {
933 //
934 // The GOP callback ran successfully and unregistered itself. Release the
935 // resources allocated there.
936 //
937 ASSERT (mGopModes != NULL);
938 FreePool (mGopModes);
939 } else {
940 //
941 // Otherwise we need to unregister the callback.
942 //
943 ASSERT (mGopModes == NULL);
944 gBS->CloseEvent (mGopEvent);
945 }
946
947 //
948 // Release resources allocated by the entry point.
949 //
950 HiiRemovePackages (mInstalledPackages);
951 gBS->UninstallMultipleProtocolInterfaces (
952 ImageHandle,
953 &gEfiDevicePathProtocolGuid,
954 &mPkgDevicePath,
955 &gEfiHiiConfigAccessProtocolGuid,
956 &mConfigAccess,
957 NULL
958 );
959 return EFI_SUCCESS;
960 }