]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformDxe/Platform.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 /**
124 Load the persistent platform configuration and translate it to binary form
125 state.
126
127 If the platform configuration is missing, then the function fills in a
128 default state.
129
130 @param[out] MainFormState Binary form/widget state after translation.
131
132 @retval EFI_SUCCESS Form/widget state ready.
133 @return Error codes from underlying functions.
134 **/
135 STATIC
136 EFI_STATUS
137 EFIAPI
138 PlatformConfigToFormState (
139 OUT MAIN_FORM_STATE *MainFormState
140 )
141 {
142 EFI_STATUS Status;
143 PLATFORM_CONFIG PlatformConfig;
144 UINT64 OptionalElements;
145 UINTN ModeNumber;
146
147 ZeroMem (MainFormState, sizeof *MainFormState);
148
149 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
150 switch (Status) {
151 case EFI_SUCCESS:
152 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
153 //
154 // Format the preferred resolution as text.
155 //
156 UnicodeSPrintAsciiFormat (
157 (CHAR16 *) MainFormState->CurrentPreferredResolution,
158 sizeof MainFormState->CurrentPreferredResolution,
159 "%Ldx%Ld",
160 (INT64) PlatformConfig.HorizontalResolution,
161 (INT64) PlatformConfig.VerticalResolution);
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 MainFormState->NextPreferredResolution = (UINT32) ModeNumber;
171 break;
172 }
173 }
174
175 break;
176 }
177 //
178 // fall through otherwise
179 //
180
181 case EFI_NOT_FOUND:
182 UnicodeSPrintAsciiFormat (
183 (CHAR16 *) MainFormState->CurrentPreferredResolution,
184 sizeof MainFormState->CurrentPreferredResolution,
185 "Unset");
186 break;
187
188 default:
189 return Status;
190 }
191
192 return EFI_SUCCESS;
193 }
194
195
196 /**
197 This function is called by the HII machinery when it fetches the form state.
198
199 See the precise documentation in the UEFI spec.
200
201 @param[in] This The Config Access Protocol instance.
202
203 @param[in] Request A <ConfigRequest> format UCS-2 string describing the
204 query.
205
206 @param[out] Progress A pointer into Request on output, identifying the query
207 element where processing failed.
208
209 @param[out] Results A <MultiConfigAltResp> format UCS-2 string that has
210 all values filled in for the names in the Request
211 string.
212
213 @retval EFI_SUCCESS Extraction of form state in <MultiConfigAltResp>
214 encoding successful.
215 @return Status codes from underlying functions.
216
217 **/
218 STATIC
219 EFI_STATUS
220 EFIAPI
221 ExtractConfig (
222 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
223 IN CONST EFI_STRING Request,
224 OUT EFI_STRING *Progress,
225 OUT EFI_STRING *Results
226 )
227 {
228 MAIN_FORM_STATE MainFormState;
229 EFI_STATUS Status;
230
231 DEBUG ((DEBUG_VERBOSE, "%a: Request=\"%s\"\n", __FUNCTION__, Request));
232
233 Status = PlatformConfigToFormState (&MainFormState);
234 if (EFI_ERROR (Status)) {
235 *Progress = Request;
236 return Status;
237 }
238
239 //
240 // Answer the textual request keying off the binary form state.
241 //
242 Status = gHiiConfigRouting->BlockToConfig (gHiiConfigRouting, Request,
243 (VOID *) &MainFormState, sizeof MainFormState,
244 Results, Progress);
245 if (EFI_ERROR (Status)) {
246 DEBUG ((DEBUG_ERROR, "%a: BlockToConfig(): %r, Progress=\"%s\"\n",
247 __FUNCTION__, Status, (Status == EFI_DEVICE_ERROR) ? NULL : *Progress));
248 } else {
249 DEBUG ((DEBUG_VERBOSE, "%a: Results=\"%s\"\n", __FUNCTION__, *Results));
250 }
251 return Status;
252 }
253
254
255 /**
256 Interpret the binary form state and save it as persistent platform
257 configuration.
258
259 @param[in] MainFormState Binary form/widget state to verify and save.
260
261 @retval EFI_SUCCESS Platform configuration saved.
262 @return Error codes from underlying functions.
263 **/
264 STATIC
265 EFI_STATUS
266 EFIAPI
267 FormStateToPlatformConfig (
268 IN CONST MAIN_FORM_STATE *MainFormState
269 )
270 {
271 EFI_STATUS Status;
272 PLATFORM_CONFIG PlatformConfig;
273 CONST GOP_MODE *GopMode;
274
275 //
276 // There's nothing to do with the textual CurrentPreferredResolution field.
277 // We verify and translate the selection in the drop-down list.
278 //
279 if (MainFormState->NextPreferredResolution >= mNumGopModes) {
280 return EFI_INVALID_PARAMETER;
281 }
282 GopMode = mGopModes + MainFormState->NextPreferredResolution;
283
284 ZeroMem (&PlatformConfig, sizeof PlatformConfig);
285 PlatformConfig.HorizontalResolution = GopMode->X;
286 PlatformConfig.VerticalResolution = GopMode->Y;
287
288 Status = PlatformConfigSave (&PlatformConfig);
289 return Status;
290 }
291
292
293 /**
294 This function is called by the HII machinery when it wants the driver to
295 interpret and persist the form state.
296
297 See the precise documentation in the UEFI spec.
298
299 @param[in] This The Config Access Protocol instance.
300
301 @param[in] Configuration A <ConfigResp> format UCS-2 string describing the
302 form state.
303
304 @param[out] Progress A pointer into Configuration on output,
305 identifying the element where processing failed.
306
307 @retval EFI_SUCCESS Configuration verified, state permanent.
308
309 @return Status codes from underlying functions.
310 **/
311 STATIC
312 EFI_STATUS
313 EFIAPI
314 RouteConfig (
315 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
316 IN CONST EFI_STRING Configuration,
317 OUT EFI_STRING *Progress
318 )
319 {
320 MAIN_FORM_STATE MainFormState;
321 UINTN BlockSize;
322 EFI_STATUS Status;
323
324 DEBUG ((DEBUG_VERBOSE, "%a: Configuration=\"%s\"\n", __FUNCTION__,
325 Configuration));
326
327 //
328 // the "read" step in RMW
329 //
330 Status = PlatformConfigToFormState (&MainFormState);
331 if (EFI_ERROR (Status)) {
332 *Progress = Configuration;
333 return Status;
334 }
335
336 //
337 // the "modify" step in RMW
338 //
339 // (Update the binary form state. This update may be partial, which is why in
340 // general we must pre-load the form state from the platform config.)
341 //
342 BlockSize = sizeof MainFormState;
343 Status = gHiiConfigRouting->ConfigToBlock (gHiiConfigRouting, Configuration,
344 (VOID *) &MainFormState, &BlockSize, Progress);
345 if (EFI_ERROR (Status)) {
346 DEBUG ((DEBUG_ERROR, "%a: ConfigToBlock(): %r, Progress=\"%s\"\n",
347 __FUNCTION__, Status,
348 (Status == EFI_BUFFER_TOO_SMALL) ? NULL : *Progress));
349 return Status;
350 }
351
352 //
353 // the "write" step in RMW
354 //
355 Status = FormStateToPlatformConfig (&MainFormState);
356 if (EFI_ERROR (Status)) {
357 *Progress = Configuration;
358 }
359 return Status;
360 }
361
362
363 STATIC
364 EFI_STATUS
365 EFIAPI
366 Callback (
367 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
368 IN EFI_BROWSER_ACTION Action,
369 IN EFI_QUESTION_ID QuestionId,
370 IN UINT8 Type,
371 IN OUT EFI_IFR_TYPE_VALUE *Value,
372 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
373 )
374 {
375 DEBUG ((DEBUG_VERBOSE, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",
376 __FUNCTION__, (UINT64) Action, QuestionId, Type));
377
378 if (Action != EFI_BROWSER_ACTION_CHANGED) {
379 return EFI_UNSUPPORTED;
380 }
381
382 switch (QuestionId) {
383 case QUESTION_SAVE_EXIT:
384 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
385 break;
386
387 case QUESTION_DISCARD_EXIT:
388 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
389 break;
390
391 default:
392 break;
393 }
394
395 return EFI_SUCCESS;
396 }
397
398
399 /**
400 Query and save all resolutions supported by the GOP.
401
402 @param[in] Gop The Graphics Output Protocol instance to query.
403
404 @param[out] NumGopModes The number of modes supported by the GOP. On output,
405 this parameter will be positive.
406
407 @param[out] GopModes On output, a dynamically allocated array containing
408 the resolutions returned by the GOP. The caller is
409 responsible for freeing the array after use.
410
411 @retval EFI_UNSUPPORTED No modes found.
412 @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes.
413 @return Error codes from Gop->QueryMode().
414
415 **/
416 STATIC
417 EFI_STATUS
418 EFIAPI
419 QueryGopModes (
420 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
421 OUT UINTN *NumGopModes,
422 OUT GOP_MODE **GopModes
423 )
424 {
425 EFI_STATUS Status;
426 UINT32 ModeNumber;
427
428 if (Gop->Mode->MaxMode == 0) {
429 return EFI_UNSUPPORTED;
430 }
431 *NumGopModes = Gop->Mode->MaxMode;
432
433 *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);
434 if (*GopModes == NULL) {
435 return EFI_OUT_OF_RESOURCES;
436 }
437
438 for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {
439 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
440 UINTN SizeOfInfo;
441
442 Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);
443 if (EFI_ERROR (Status)) {
444 goto FreeGopModes;
445 }
446
447 (*GopModes)[ModeNumber].X = Info->HorizontalResolution;
448 (*GopModes)[ModeNumber].Y = Info->VerticalResolution;
449 FreePool (Info);
450 }
451
452 return EFI_SUCCESS;
453
454 FreeGopModes:
455 FreePool (*GopModes);
456
457 return Status;
458 }
459
460
461 /**
462 Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
463 based on available GOP resolutions, to be placed under a "one-of-many" (ie.
464 "drop down list") opcode.
465
466 @param[in] PackageList The package list with the formset and form for
467 which the drop down options are produced. Option
468 names are added as new strings to PackageList.
469
470 @param[out] OpCodeBuffer On output, a dynamically allocated opcode buffer
471 with drop down list options corresponding to GOP
472 resolutions. The caller is responsible for freeing
473 OpCodeBuffer with HiiFreeOpCodeHandle() after use.
474
475 @param[in] NumGopModes Number of entries in GopModes.
476
477 @param[in] GopModes Array of resolutions retrieved from the GOP.
478
479 @retval EFI_SUCESS Opcodes have been successfully produced.
480
481 @return Status codes from underlying functions. PackageList may
482 have been extended with new strings. OpCodeBuffer is
483 unchanged.
484 **/
485 STATIC
486 EFI_STATUS
487 EFIAPI
488 CreateResolutionOptions (
489 IN EFI_HII_HANDLE PackageList,
490 OUT VOID **OpCodeBuffer,
491 IN UINTN NumGopModes,
492 IN GOP_MODE *GopModes
493 )
494 {
495 EFI_STATUS Status;
496 VOID *OutputBuffer;
497 UINTN ModeNumber;
498
499 OutputBuffer = HiiAllocateOpCodeHandle ();
500 if (OutputBuffer == NULL) {
501 return EFI_OUT_OF_RESOURCES;
502 }
503
504 for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {
505 CHAR16 Desc[MAXSIZE_RES_CUR];
506 EFI_STRING_ID NewString;
507 VOID *OpCode;
508
509 UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",
510 (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);
511 NewString = HiiSetString (PackageList, 0 /* new string */, Desc,
512 NULL /* for all languages */);
513 if (NewString == 0) {
514 Status = EFI_OUT_OF_RESOURCES;
515 goto FreeOutputBuffer;
516 }
517 OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,
518 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);
519 if (OpCode == NULL) {
520 Status = EFI_OUT_OF_RESOURCES;
521 goto FreeOutputBuffer;
522 }
523 }
524
525 *OpCodeBuffer = OutputBuffer;
526 return EFI_SUCCESS;
527
528 FreeOutputBuffer:
529 HiiFreeOpCodeHandle (OutputBuffer);
530
531 return Status;
532 }
533
534
535 /**
536 Populate the form identified by the (PackageList, FormSetGuid, FormId)
537 triplet.
538
539 The drop down list of video resolutions is generated from (NumGopModes,
540 GopModes).
541
542 @retval EFI_SUCESS Form successfully updated.
543 @return Status codes from underlying functions.
544
545 **/
546 STATIC
547 EFI_STATUS
548 EFIAPI
549 PopulateForm (
550 IN EFI_HII_HANDLE PackageList,
551 IN EFI_GUID *FormSetGuid,
552 IN EFI_FORM_ID FormId,
553 IN UINTN NumGopModes,
554 IN GOP_MODE *GopModes
555 )
556 {
557 EFI_STATUS Status;
558 VOID *OpCodeBuffer;
559 VOID *OpCode;
560 EFI_IFR_GUID_LABEL *Anchor;
561 VOID *OpCodeBuffer2;
562
563 OpCodeBuffer2 = NULL;
564
565 //
566 // 1. Allocate an empty opcode buffer.
567 //
568 OpCodeBuffer = HiiAllocateOpCodeHandle ();
569 if (OpCodeBuffer == NULL) {
570 return EFI_OUT_OF_RESOURCES;
571 }
572
573 //
574 // 2. Create a label opcode (which is a Tiano extension) inside the buffer.
575 // The label's number must match the "anchor" label in the form.
576 //
577 OpCode = HiiCreateGuidOpCode (OpCodeBuffer, &gEfiIfrTianoGuid,
578 NULL /* optional copy origin */, sizeof *Anchor);
579 if (OpCode == NULL) {
580 Status = EFI_OUT_OF_RESOURCES;
581 goto FreeOpCodeBuffer;
582 }
583 Anchor = OpCode;
584 Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
585 Anchor->Number = LABEL_RES_NEXT;
586
587 //
588 // 3. Create the opcodes inside the buffer that are to be inserted into the
589 // form.
590 //
591 // 3.1. Get a list of resolutions.
592 //
593 Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2,
594 NumGopModes, GopModes);
595 if (EFI_ERROR (Status)) {
596 goto FreeOpCodeBuffer;
597 }
598
599 //
600 // 3.2. Create a one-of-many question with the above options.
601 //
602 OpCode = HiiCreateOneOfOpCode (
603 OpCodeBuffer, // create opcode inside this
604 // opcode buffer,
605 QUESTION_RES_NEXT, // ID of question,
606 FORMSTATEID_MAIN_FORM, // identifies form state
607 // storage,
608 (UINT16) OFFSET_OF (MAIN_FORM_STATE, // value of question stored
609 NextPreferredResolution), // at this offset,
610 STRING_TOKEN (STR_RES_NEXT), // Prompt,
611 STRING_TOKEN (STR_RES_NEXT_HELP), // Help,
612 0, // QuestionFlags,
613 EFI_IFR_NUMERIC_SIZE_4, // see sizeof
614 // NextPreferredResolution,
615 OpCodeBuffer2, // buffer with possible
616 // choices,
617 NULL // DEFAULT opcodes
618 );
619 if (OpCode == NULL) {
620 Status = EFI_OUT_OF_RESOURCES;
621 goto FreeOpCodeBuffer2;
622 }
623
624 //
625 // 4. Update the form with the opcode buffer.
626 //
627 Status = HiiUpdateForm (PackageList, FormSetGuid, FormId,
628 OpCodeBuffer, // buffer with head anchor, and new contents to be
629 // inserted at it
630 NULL // buffer with tail anchor, for deleting old
631 // contents up to it
632 );
633
634 FreeOpCodeBuffer2:
635 HiiFreeOpCodeHandle (OpCodeBuffer2);
636
637 FreeOpCodeBuffer:
638 HiiFreeOpCodeHandle (OpCodeBuffer);
639
640 return Status;
641 }
642
643
644 /**
645 Load and execute the platform configuration.
646
647 @retval EFI_SUCCESS Configuration loaded and executed.
648 @return Status codes from PlatformConfigLoad().
649 **/
650 STATIC
651 EFI_STATUS
652 EFIAPI
653 ExecutePlatformConfig (
654 VOID
655 )
656 {
657 EFI_STATUS Status;
658 PLATFORM_CONFIG PlatformConfig;
659 UINT64 OptionalElements;
660 RETURN_STATUS PcdStatus;
661
662 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
663 if (EFI_ERROR (Status)) {
664 DEBUG (((Status == EFI_NOT_FOUND) ? DEBUG_VERBOSE : DEBUG_ERROR,
665 "%a: failed to load platform config: %r\n", __FUNCTION__, Status));
666 return Status;
667 }
668
669 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
670 //
671 // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.
672 //
673 PcdStatus = PcdSet32S (PcdVideoHorizontalResolution,
674 PlatformConfig.HorizontalResolution);
675 ASSERT_RETURN_ERROR (PcdStatus);
676
677 PcdStatus = PcdSet32S (PcdVideoVerticalResolution,
678 PlatformConfig.VerticalResolution);
679 ASSERT_RETURN_ERROR (PcdStatus);
680 }
681
682 return EFI_SUCCESS;
683 }
684
685
686 /**
687 Notification callback for GOP interface installation.
688
689 @param[in] Event Event whose notification function is being invoked.
690
691 @param[in] Context The pointer to the notification function's context, which
692 is implementation-dependent.
693 **/
694 STATIC
695 VOID
696 EFIAPI
697 GopInstalled (
698 IN EFI_EVENT Event,
699 IN VOID *Context
700 )
701 {
702 EFI_STATUS Status;
703 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
704
705 ASSERT (Event == mGopEvent);
706
707 //
708 // Check further GOPs.
709 //
710 for (;;) {
711 mNumGopModes = 0;
712 mGopModes = NULL;
713
714 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,
715 (VOID **) &Gop);
716 if (EFI_ERROR (Status)) {
717 return;
718 }
719
720 Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);
721 if (EFI_ERROR (Status)) {
722 continue;
723 }
724
725 Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid,
726 FORMID_MAIN_FORM, mNumGopModes, mGopModes);
727 if (EFI_ERROR (Status)) {
728 FreePool (mGopModes);
729 continue;
730 }
731
732 break;
733 }
734
735 //
736 // Success -- so uninstall this callback. Closing the event removes all
737 // pending notifications and all protocol registrations.
738 //
739 Status = gBS->CloseEvent (mGopEvent);
740 ASSERT_EFI_ERROR (Status);
741 mGopEvent = NULL;
742 mGopTracker = NULL;
743 }
744
745
746 /**
747 Entry point for this driver.
748
749 @param[in] ImageHandle Image handle of this driver.
750 @param[in] SystemTable Pointer to SystemTable.
751
752 @retval EFI_SUCESS Driver has loaded successfully.
753 @retval EFI_OUT_OF_RESOURCES Failed to install HII packages.
754 @return Error codes from lower level functions.
755
756 **/
757 EFI_STATUS
758 EFIAPI
759 PlatformInit (
760 IN EFI_HANDLE ImageHandle,
761 IN EFI_SYSTEM_TABLE *SystemTable
762 )
763 {
764 EFI_STATUS Status;
765
766 ExecutePlatformConfig ();
767
768 mConfigAccess.ExtractConfig = &ExtractConfig;
769 mConfigAccess.RouteConfig = &RouteConfig;
770 mConfigAccess.Callback = &Callback;
771
772 //
773 // Declare ourselves suitable for HII communication.
774 //
775 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
776 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,
777 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
778 NULL);
779 if (EFI_ERROR (Status)) {
780 return Status;
781 }
782
783 //
784 // Publish the HII package list to HII Database.
785 //
786 mInstalledPackages = HiiAddPackages (
787 &gEfiCallerIdGuid, // PackageListGuid
788 ImageHandle, // associated DeviceHandle
789 PlatformDxeStrings, // 1st package
790 PlatformFormsBin, // 2nd package
791 NULL // terminator
792 );
793 if (mInstalledPackages == NULL) {
794 Status = EFI_OUT_OF_RESOURCES;
795 goto UninstallProtocols;
796 }
797
798 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,
799 NULL /* Context */, &mGopEvent);
800 if (EFI_ERROR (Status)) {
801 goto RemovePackages;
802 }
803
804 Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,
805 mGopEvent, &mGopTracker);
806 if (EFI_ERROR (Status)) {
807 goto CloseGopEvent;
808 }
809
810 //
811 // Check already installed GOPs.
812 //
813 Status = gBS->SignalEvent (mGopEvent);
814 ASSERT_EFI_ERROR (Status);
815
816 return EFI_SUCCESS;
817
818 CloseGopEvent:
819 gBS->CloseEvent (mGopEvent);
820
821 RemovePackages:
822 HiiRemovePackages (mInstalledPackages);
823
824 UninstallProtocols:
825 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
826 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,
827 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
828 NULL);
829 return Status;
830 }
831
832 /**
833 Unload the driver.
834
835 @param[in] ImageHandle Handle that identifies the image to evict.
836
837 @retval EFI_SUCCESS The image has been unloaded.
838 **/
839 EFI_STATUS
840 EFIAPI
841 PlatformUnload (
842 IN EFI_HANDLE ImageHandle
843 )
844 {
845 if (mGopEvent == NULL) {
846 //
847 // The GOP callback ran successfully and unregistered itself. Release the
848 // resources allocated there.
849 //
850 ASSERT (mGopModes != NULL);
851 FreePool (mGopModes);
852 } else {
853 //
854 // Otherwise we need to unregister the callback.
855 //
856 ASSERT (mGopModes == NULL);
857 gBS->CloseEvent (mGopEvent);
858 }
859
860 //
861 // Release resources allocated by the entry point.
862 //
863 HiiRemovePackages (mInstalledPackages);
864 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
865 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,
866 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,
867 NULL);
868 return EFI_SUCCESS;
869 }