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