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