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