]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PlatformDxe/Platform.c
OvmfPkg: PlatformDxe: connect ExtractConfig() to platform data
[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
261STATIC\r
262EFI_STATUS\r
263EFIAPI\r
264RouteConfig (\r
265 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
266 IN CONST EFI_STRING Configuration,\r
267 OUT EFI_STRING *Progress\r
268)\r
269{\r
1df57ba3
LE
270 DEBUG ((EFI_D_VERBOSE, "%a: Configuration=\"%s\"\n", __FUNCTION__,\r
271 Configuration));\r
877a4dbb
LE
272 return EFI_SUCCESS;\r
273}\r
274\r
275\r
276STATIC\r
277EFI_STATUS\r
278EFIAPI\r
279Callback (\r
280 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
281 IN EFI_BROWSER_ACTION Action,\r
282 IN EFI_QUESTION_ID QuestionId,\r
283 IN UINT8 Type,\r
284 IN OUT EFI_IFR_TYPE_VALUE *Value,\r
285 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
286 )\r
287{\r
1df57ba3
LE
288 DEBUG ((EFI_D_VERBOSE, "%a: Action=0x%Lx QuestionId=%d Type=%d\n",\r
289 __FUNCTION__, (UINT64) Action, QuestionId, Type));\r
290\r
291 if (Action != EFI_BROWSER_ACTION_CHANGED) {\r
292 return EFI_UNSUPPORTED;\r
293 }\r
294\r
295 switch (QuestionId) {\r
296 case QUESTION_SAVE_EXIT:\r
297 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;\r
298 break;\r
299\r
300 case QUESTION_DISCARD_EXIT:\r
301 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;\r
302 break;\r
303\r
304 default:\r
305 break;\r
306 }\r
307\r
877a4dbb
LE
308 return EFI_SUCCESS;\r
309}\r
310\r
311\r
da07afaf
LE
312/**\r
313 Query and save all resolutions supported by the GOP.\r
314\r
315 @param[in] Gop The Graphics Output Protocol instance to query.\r
316\r
317 @param[out] NumGopModes The number of modes supported by the GOP. On output,\r
318 this parameter will be positive.\r
319\r
320 @param[out] GopModes On output, a dynamically allocated array containing\r
321 the resolutions returned by the GOP. The caller is\r
322 responsible for freeing the array after use.\r
323\r
324 @retval EFI_UNSUPPORTED No modes found.\r
325 @retval EFI_OUT_OF_RESOURCES Failed to allocate GopModes.\r
326 @return Error codes from Gop->QueryMode().\r
327\r
328**/\r
329STATIC\r
330EFI_STATUS\r
331EFIAPI\r
332QueryGopModes (\r
333 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,\r
334 OUT UINTN *NumGopModes,\r
335 OUT GOP_MODE **GopModes\r
336 )\r
337{\r
338 EFI_STATUS Status;\r
339 UINT32 ModeNumber;\r
340\r
341 if (Gop->Mode->MaxMode == 0) {\r
342 return EFI_UNSUPPORTED;\r
343 }\r
344 *NumGopModes = Gop->Mode->MaxMode;\r
345\r
346 *GopModes = AllocatePool (Gop->Mode->MaxMode * sizeof **GopModes);\r
347 if (*GopModes == NULL) {\r
348 return EFI_OUT_OF_RESOURCES;\r
349 }\r
350\r
351 for (ModeNumber = 0; ModeNumber < Gop->Mode->MaxMode; ++ModeNumber) {\r
352 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
353 UINTN SizeOfInfo;\r
354\r
355 Status = Gop->QueryMode (Gop, ModeNumber, &SizeOfInfo, &Info);\r
356 if (EFI_ERROR (Status)) {\r
357 goto FreeGopModes;\r
358 }\r
359\r
360 (*GopModes)[ModeNumber].X = Info->HorizontalResolution;\r
361 (*GopModes)[ModeNumber].Y = Info->VerticalResolution;\r
362 FreePool (Info);\r
363 }\r
364\r
365 return EFI_SUCCESS;\r
366\r
367FreeGopModes:\r
368 FreePool (*GopModes);\r
369\r
370 return Status;\r
371}\r
372\r
373\r
92e74550
LE
374/**\r
375 Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,\r
376 based on available GOP resolutions, to be placed under a "one-of-many" (ie.\r
377 "drop down list") opcode.\r
378\r
379 @param[in] PackageList The package list with the formset and form for\r
380 which the drop down options are produced. Option\r
381 names are added as new strings to PackageList.\r
382\r
383 @param[out] OpCodeBuffer On output, a dynamically allocated opcode buffer\r
384 with drop down list options corresponding to GOP\r
385 resolutions. The caller is responsible for freeing\r
386 OpCodeBuffer with HiiFreeOpCodeHandle() after use.\r
387\r
da07afaf
LE
388 @param[in] NumGopModes Number of entries in GopModes.\r
389\r
390 @param[in] GopModes Array of resolutions retrieved from the GOP.\r
391\r
92e74550
LE
392 @retval EFI_SUCESS Opcodes have been successfully produced.\r
393\r
394 @return Status codes from underlying functions. PackageList may\r
395 have been extended with new strings. OpCodeBuffer is\r
396 unchanged.\r
397**/\r
398STATIC\r
399EFI_STATUS\r
400EFIAPI\r
401CreateResolutionOptions (\r
402 IN EFI_HII_HANDLE *PackageList,\r
da07afaf
LE
403 OUT VOID **OpCodeBuffer,\r
404 IN UINTN NumGopModes,\r
405 IN GOP_MODE *GopModes\r
92e74550
LE
406 )\r
407{\r
da07afaf
LE
408 EFI_STATUS Status;\r
409 VOID *OutputBuffer;\r
410 UINTN ModeNumber;\r
92e74550
LE
411\r
412 OutputBuffer = HiiAllocateOpCodeHandle ();\r
413 if (OutputBuffer == NULL) {\r
414 return EFI_OUT_OF_RESOURCES;\r
415 }\r
416\r
da07afaf
LE
417 for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {\r
418 CHAR16 Desc[MAXSIZE_RES_CUR];\r
419 EFI_STRING_ID NewString;\r
420 VOID *OpCode;\r
421\r
422 UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",\r
423 (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);\r
424 NewString = HiiSetString (PackageList, 0 /* new string */, Desc,\r
425 NULL /* for all languages */);\r
426 if (NewString == 0) {\r
427 Status = EFI_OUT_OF_RESOURCES;\r
428 goto FreeOutputBuffer;\r
429 }\r
430 OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,\r
431 0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);\r
432 if (OpCode == NULL) {\r
433 Status = EFI_OUT_OF_RESOURCES;\r
434 goto FreeOutputBuffer;\r
435 }\r
92e74550
LE
436 }\r
437\r
438 *OpCodeBuffer = OutputBuffer;\r
439 return EFI_SUCCESS;\r
440\r
441FreeOutputBuffer:\r
442 HiiFreeOpCodeHandle (OutputBuffer);\r
443\r
444 return Status;\r
445}\r
446\r
447\r
448/**\r
449 Populate the form identified by the (PackageList, FormSetGuid, FormId)\r
450 triplet.\r
451\r
da07afaf
LE
452 The drop down list of video resolutions is generated from (NumGopModes,\r
453 GopModes).\r
454\r
92e74550
LE
455 @retval EFI_SUCESS Form successfully updated.\r
456 @return Status codes from underlying functions.\r
457\r
458**/\r
459STATIC\r
460EFI_STATUS\r
461EFIAPI\r
462PopulateForm (\r
463 IN EFI_HII_HANDLE *PackageList,\r
464 IN EFI_GUID *FormSetGuid,\r
da07afaf
LE
465 IN EFI_FORM_ID FormId,\r
466 IN UINTN NumGopModes,\r
467 IN GOP_MODE *GopModes\r
92e74550
LE
468 )\r
469{\r
470 EFI_STATUS Status;\r
471 VOID *OpCodeBuffer;\r
472 VOID *OpCode;\r
473 EFI_IFR_GUID_LABEL *Anchor;\r
474 VOID *OpCodeBuffer2;\r
475\r
bc4c5366
JJ
476 OpCodeBuffer2 = NULL;\r
477\r
92e74550
LE
478 //\r
479 // 1. Allocate an empty opcode buffer.\r
480 //\r
481 OpCodeBuffer = HiiAllocateOpCodeHandle ();\r
482 if (OpCodeBuffer == NULL) {\r
483 return EFI_OUT_OF_RESOURCES;\r
484 }\r
485\r
486 //\r
487 // 2. Create a label opcode (which is a Tiano extension) inside the buffer.\r
488 // The label's number must match the "anchor" label in the form.\r
489 //\r
490 OpCode = HiiCreateGuidOpCode (OpCodeBuffer, &gEfiIfrTianoGuid,\r
491 NULL /* optional copy origin */, sizeof *Anchor);\r
492 if (OpCode == NULL) {\r
493 Status = EFI_OUT_OF_RESOURCES;\r
494 goto FreeOpCodeBuffer;\r
495 }\r
496 Anchor = OpCode;\r
497 Anchor->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
498 Anchor->Number = LABEL_RES_NEXT;\r
499\r
500 //\r
501 // 3. Create the opcodes inside the buffer that are to be inserted into the\r
502 // form.\r
503 //\r
504 // 3.1. Get a list of resolutions.\r
505 //\r
da07afaf
LE
506 Status = CreateResolutionOptions (PackageList, &OpCodeBuffer2,\r
507 NumGopModes, GopModes);\r
92e74550
LE
508 if (EFI_ERROR (Status)) {\r
509 goto FreeOpCodeBuffer;\r
510 }\r
511\r
512 //\r
513 // 3.2. Create a one-of-many question with the above options.\r
514 //\r
515 OpCode = HiiCreateOneOfOpCode (\r
516 OpCodeBuffer, // create opcode inside this\r
517 // opcode buffer,\r
518 QUESTION_RES_NEXT, // ID of question,\r
519 FORMSTATEID_MAIN_FORM, // identifies form state\r
520 // storage,\r
521 (UINT16) OFFSET_OF (MAIN_FORM_STATE, // value of question stored\r
522 NextPreferredResolution), // at this offset,\r
523 STRING_TOKEN (STR_RES_NEXT), // Prompt,\r
524 STRING_TOKEN (STR_RES_NEXT_HELP), // Help,\r
525 0, // QuestionFlags,\r
526 EFI_IFR_NUMERIC_SIZE_4, // see sizeof\r
527 // NextPreferredResolution,\r
528 OpCodeBuffer2, // buffer with possible\r
529 // choices,\r
530 NULL // DEFAULT opcodes\r
531 );\r
532 if (OpCode == NULL) {\r
533 Status = EFI_OUT_OF_RESOURCES;\r
534 goto FreeOpCodeBuffer2;\r
535 }\r
536\r
537 //\r
538 // 4. Update the form with the opcode buffer.\r
539 //\r
540 Status = HiiUpdateForm (PackageList, FormSetGuid, FormId,\r
541 OpCodeBuffer, // buffer with head anchor, and new contents to be\r
542 // inserted at it\r
543 NULL // buffer with tail anchor, for deleting old\r
544 // contents up to it\r
545 );\r
546\r
547FreeOpCodeBuffer2:\r
548 HiiFreeOpCodeHandle (OpCodeBuffer2);\r
549\r
550FreeOpCodeBuffer:\r
551 HiiFreeOpCodeHandle (OpCodeBuffer);\r
552\r
553 return Status;\r
554}\r
555\r
556\r
bdaf30e4
LE
557/**\r
558 Load and execute the platform configuration.\r
559\r
560 @retval EFI_SUCCESS Configuration loaded and executed.\r
561 @return Status codes from PlatformConfigLoad().\r
562**/\r
563STATIC\r
564EFI_STATUS\r
565EFIAPI\r
566ExecutePlatformConfig (\r
567 VOID\r
568 )\r
569{\r
570 EFI_STATUS Status;\r
571 PLATFORM_CONFIG PlatformConfig;\r
572 UINT64 OptionalElements;\r
573\r
574 Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);\r
575 if (EFI_ERROR (Status)) {\r
576 DEBUG (((Status == EFI_NOT_FOUND) ? EFI_D_VERBOSE : EFI_D_ERROR,\r
577 "%a: failed to load platform config: %r\n", __FUNCTION__, Status));\r
578 return Status;\r
579 }\r
580\r
581 if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {\r
582 //\r
583 // Pass the preferred resolution to GraphicsConsoleDxe via dynamic PCDs.\r
584 //\r
585 PcdSet32 (PcdVideoHorizontalResolution,\r
586 PlatformConfig.HorizontalResolution);\r
587 PcdSet32 (PcdVideoVerticalResolution,\r
588 PlatformConfig.VerticalResolution);\r
589 }\r
590\r
591 return EFI_SUCCESS;\r
592}\r
593\r
594\r
da07afaf
LE
595/**\r
596 Notification callback for GOP interface installation.\r
597\r
598 @param[in] Event Event whose notification function is being invoked.\r
599\r
600 @param[in] Context The pointer to the notification function's context, which\r
601 is implementation-dependent.\r
602**/\r
603STATIC\r
604VOID\r
605EFIAPI\r
606GopInstalled (\r
607 IN EFI_EVENT Event,\r
608 IN VOID *Context\r
609 )\r
610{\r
611 EFI_STATUS Status;\r
612 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
613\r
614 ASSERT (Event == mGopEvent);\r
615\r
616 //\r
617 // Check further GOPs.\r
618 //\r
619 for (;;) {\r
620 mNumGopModes = 0;\r
621 mGopModes = NULL;\r
622\r
623 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, mGopTracker,\r
624 (VOID **) &Gop);\r
625 if (EFI_ERROR (Status)) {\r
626 return;\r
627 }\r
628\r
629 Status = QueryGopModes (Gop, &mNumGopModes, &mGopModes);\r
630 if (EFI_ERROR (Status)) {\r
631 continue;\r
632 }\r
633\r
634 Status = PopulateForm (mInstalledPackages, &gOvmfPlatformConfigGuid,\r
635 FORMID_MAIN_FORM, mNumGopModes, mGopModes);\r
636 if (EFI_ERROR (Status)) {\r
637 FreePool (mGopModes);\r
638 continue;\r
639 }\r
640\r
641 break;\r
642 }\r
643\r
644 //\r
645 // Success -- so uninstall this callback. Closing the event removes all\r
646 // pending notifications and all protocol registrations.\r
647 //\r
648 Status = gBS->CloseEvent (mGopEvent);\r
649 ASSERT_EFI_ERROR (Status);\r
650 mGopEvent = NULL;\r
651 mGopTracker = NULL;\r
652}\r
653\r
654\r
d945a8ba
LE
655/**\r
656 Entry point for this driver.\r
657\r
658 @param[in] ImageHandle Image handle of this driver.\r
659 @param[in] SystemTable Pointer to SystemTable.\r
660\r
661 @retval EFI_SUCESS Driver has loaded successfully.\r
877a4dbb
LE
662 @retval EFI_OUT_OF_RESOURCES Failed to install HII packages.\r
663 @return Error codes from lower level functions.\r
d945a8ba
LE
664\r
665**/\r
666EFI_STATUS\r
667EFIAPI\r
668PlatformInit (\r
669 IN EFI_HANDLE ImageHandle,\r
670 IN EFI_SYSTEM_TABLE *SystemTable\r
671 )\r
672{\r
877a4dbb
LE
673 EFI_STATUS Status;\r
674\r
bdaf30e4 675 ExecutePlatformConfig ();\r
877a4dbb
LE
676\r
677 mConfigAccess.ExtractConfig = &ExtractConfig;\r
678 mConfigAccess.RouteConfig = &RouteConfig;\r
679 mConfigAccess.Callback = &Callback;\r
680\r
681 //\r
682 // Declare ourselves suitable for HII communication.\r
683 //\r
684 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,\r
685 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
686 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
687 NULL);\r
688 if (EFI_ERROR (Status)) {\r
689 return Status;\r
690 }\r
691\r
692 //\r
693 // Publish the HII package list to HII Database.\r
694 //\r
695 mInstalledPackages = HiiAddPackages (\r
696 &gEfiCallerIdGuid, // PackageListGuid\r
697 ImageHandle, // associated DeviceHandle\r
698 PlatformDxeStrings, // 1st package\r
699 PlatformFormsBin, // 2nd package\r
700 NULL // terminator\r
701 );\r
702 if (mInstalledPackages == NULL) {\r
703 Status = EFI_OUT_OF_RESOURCES;\r
704 goto UninstallProtocols;\r
705 }\r
706\r
da07afaf
LE
707 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, &GopInstalled,\r
708 NULL /* Context */, &mGopEvent);\r
92e74550
LE
709 if (EFI_ERROR (Status)) {\r
710 goto RemovePackages;\r
711 }\r
712\r
da07afaf
LE
713 Status = gBS->RegisterProtocolNotify (&gEfiGraphicsOutputProtocolGuid,\r
714 mGopEvent, &mGopTracker);\r
715 if (EFI_ERROR (Status)) {\r
716 goto CloseGopEvent;\r
717 }\r
718\r
719 //\r
720 // Check already installed GOPs.\r
721 //\r
722 Status = gBS->SignalEvent (mGopEvent);\r
723 ASSERT_EFI_ERROR (Status);\r
724\r
d945a8ba 725 return EFI_SUCCESS;\r
877a4dbb 726\r
da07afaf
LE
727CloseGopEvent:\r
728 gBS->CloseEvent (mGopEvent);\r
729\r
92e74550
LE
730RemovePackages:\r
731 HiiRemovePackages (mInstalledPackages);\r
732\r
877a4dbb
LE
733UninstallProtocols:\r
734 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,\r
735 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
736 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
737 NULL);\r
738 return Status;\r
d945a8ba
LE
739}\r
740\r
741/**\r
742 Unload the driver.\r
743\r
744 @param[in] ImageHandle Handle that identifies the image to evict.\r
745\r
746 @retval EFI_SUCCESS The image has been unloaded.\r
747**/\r
748EFI_STATUS\r
749EFIAPI\r
750PlatformUnload (\r
751 IN EFI_HANDLE ImageHandle\r
752 )\r
753{\r
da07afaf
LE
754 if (mGopEvent == NULL) {\r
755 //\r
756 // The GOP callback ran successfully and unregistered itself. Release the\r
757 // resources allocated there.\r
758 //\r
759 ASSERT (mGopModes != NULL);\r
760 FreePool (mGopModes);\r
761 } else {\r
762 //\r
763 // Otherwise we need to unregister the callback.\r
764 //\r
765 ASSERT (mGopModes == NULL);\r
766 gBS->CloseEvent (mGopEvent);\r
767 }\r
768\r
769 //\r
770 // Release resources allocated by the entry point.\r
771 //\r
877a4dbb
LE
772 HiiRemovePackages (mInstalledPackages);\r
773 gBS->UninstallMultipleProtocolInterfaces (ImageHandle,\r
774 &gEfiDevicePathProtocolGuid, &mPkgDevicePath,\r
775 &gEfiHiiConfigAccessProtocolGuid, &mConfigAccess,\r
776 NULL);\r
d945a8ba
LE
777 return EFI_SUCCESS;\r
778}\r