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