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