newline added at end
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMngr / BootManager.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name: \r
13 \r
14   BootManager.c\r
15 \r
16 Abstract:\r
17 \r
18   The platform boot manager reference implement\r
19 \r
20 --*/\r
21 #include "BootManager.h"\r
22 \r
23 UINT16                            mKeyInput;\r
24 LIST_ENTRY                        *mBootOptionsList;\r
25 BDS_COMMON_OPTION                 *gOption;\r
26 EFI_HII_HANDLE                    gBootManagerHandle;\r
27 EFI_HANDLE                        BootManagerCallbackHandle;\r
28 EFI_FORM_CALLBACK_PROTOCOL        BootManagerCallback;\r
29 EFI_GUID                          gBmGuid = BOOT_MANAGER_GUID;\r
30 \r
31 extern EFI_FORM_BROWSER_PROTOCOL  *gBrowser;\r
32 extern UINT8                      BootManagerVfrBin[];\r
33 extern UINT8                      BdsStrings[];\r
34 extern BOOLEAN                    gConnectAllHappened;\r
35 \r
36 EFI_STATUS\r
37 EFIAPI\r
38 BootManagerCallbackRoutine (\r
39   IN EFI_FORM_CALLBACK_PROTOCOL       *This,\r
40   IN UINT16                           KeyValue,\r
41   IN EFI_IFR_DATA_ARRAY               *DataArray,\r
42   OUT EFI_HII_CALLBACK_PACKET         **Packet\r
43   )\r
44 /*++\r
45 \r
46 Routine Description:\r
47 \r
48   This is the function that is called to provide results data to the driver.  This data\r
49   consists of a unique key which is used to identify what data is either being passed back\r
50   or being asked for. \r
51 \r
52 Arguments:\r
53 \r
54   KeyValue -        A unique value which is sent to the original exporting driver so that it\r
55                     can identify the type of data to expect.  The format of the data tends to\r
56                     vary based on the op-code that geerated the callback.\r
57 \r
58   Data -            A pointer to the data being sent to the original exporting driver.\r
59 \r
60 Returns: \r
61 \r
62 --*/\r
63 {\r
64   BDS_COMMON_OPTION       *Option;\r
65   LIST_ENTRY              *Link;\r
66   UINT16                  KeyCount;\r
67   EFI_HII_CALLBACK_PACKET *DataPacket;\r
68 \r
69   //\r
70   // Initialize the key count\r
71   //\r
72   KeyCount = 0;\r
73 \r
74   for (Link = mBootOptionsList->ForwardLink; Link != mBootOptionsList; Link = Link->ForwardLink) {\r
75     Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
76 \r
77     KeyCount++;\r
78 \r
79     gOption = Option;\r
80 \r
81     //\r
82     // Is this device the one chosen?\r
83     //\r
84     if (KeyCount == KeyValue) {\r
85       //\r
86       // Assigning the returned Key to a global allows the original routine to know what was chosen\r
87       //\r
88       mKeyInput = KeyValue;\r
89 \r
90       *Packet   = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2);\r
91       ASSERT (*Packet != NULL);\r
92 \r
93       //\r
94       // Assign the buffer address to DataPacket\r
95       //\r
96       DataPacket                        = *Packet;\r
97 \r
98       DataPacket->DataArray.EntryCount  = 1;\r
99       DataPacket->DataArray.NvRamMap    = NULL;\r
100       ((EFI_IFR_DATA_ENTRY *) (((EFI_IFR_DATA_ARRAY *)DataPacket) + 1))->Flags = EXIT_REQUIRED | NV_NOT_CHANGED;\r
101       return EFI_SUCCESS;\r
102     } else {\r
103       continue;\r
104     }\r
105   }\r
106 \r
107   return EFI_SUCCESS;\r
108 }\r
109 \r
110 VOID\r
111 CallBootManager (\r
112   VOID\r
113   )\r
114 /*++\r
115 \r
116 Routine Description:\r
117   Hook to enable UI timeout override behavior.\r
118 \r
119 Arguments:\r
120   BdsDeviceList - Device List that BDS needs to connect.\r
121 \r
122   Entry - Pointer to current Boot Entry.\r
123 \r
124 Returns:\r
125   NONE\r
126 \r
127 --*/\r
128 {\r
129   EFI_STATUS          Status;\r
130   EFI_HII_PACKAGES    *PackageList;\r
131   BDS_COMMON_OPTION   *Option;\r
132   LIST_ENTRY          *Link;\r
133   EFI_HII_UPDATE_DATA *UpdateData;\r
134   CHAR16              *ExitData;\r
135   UINTN               ExitDataSize;\r
136   STRING_REF          Token;\r
137   STRING_REF          LastToken;\r
138   EFI_INPUT_KEY       Key;\r
139   UINT8               *Location;\r
140   EFI_GUID            BmGuid;\r
141   LIST_ENTRY          BdsBootOptionList;\r
142   BOOLEAN                 BootMngrMenuResetRequired;\r
143 \r
144   gOption = NULL;\r
145   InitializeListHead (&BdsBootOptionList);\r
146 \r
147   //\r
148   // Connect all prior to entering the platform setup menu.\r
149   //\r
150   if (!gConnectAllHappened) {\r
151     BdsLibConnectAllDriversToAllControllers ();\r
152     gConnectAllHappened = TRUE;\r
153   }\r
154   //\r
155   // BugBug: Here we can not remove the legacy refresh macro, so we need\r
156   // get the boot order every time from "BootOrder" variable.\r
157   // Recreate the boot option list base on the BootOrder variable\r
158   //\r
159   BdsLibEnumerateAllBootOption (&BdsBootOptionList);\r
160 \r
161   //\r
162   // This GUID must be the same as what is defined in BootManagerVfr.vfr\r
163   //\r
164   BmGuid            = gBmGuid;\r
165 \r
166   mBootOptionsList  = &BdsBootOptionList;\r
167 \r
168   //\r
169   // Post our VFR to the HII database\r
170   //\r
171   PackageList = PreparePackages (2, &BmGuid, BootManagerVfrBin, BdsStrings);\r
172   Status      = Hii->NewPack (Hii, PackageList, &gBootManagerHandle);\r
173   gBS->FreePool (PackageList);\r
174 \r
175   //\r
176   // This example does not implement worker functions\r
177   // for the NV accessor functions.  Only a callback evaluator\r
178   //\r
179   BootManagerCallback.NvRead    = NULL;\r
180   BootManagerCallback.NvWrite   = NULL;\r
181   BootManagerCallback.Callback  = BootManagerCallbackRoutine;\r
182 \r
183   //\r
184   // Install protocol interface\r
185   //\r
186   BootManagerCallbackHandle = NULL;\r
187   Status = gBS->InstallProtocolInterface (\r
188                   &BootManagerCallbackHandle,\r
189                   &gEfiFormCallbackProtocolGuid,\r
190                   EFI_NATIVE_INTERFACE,\r
191                   &BootManagerCallback\r
192                   );\r
193   ASSERT_EFI_ERROR (Status);\r
194 \r
195   LastToken = 0;\r
196   Hii->NewString (Hii, NULL, gBootManagerHandle, &LastToken, L" ");\r
197 \r
198   //\r
199   // Allocate space for creation of UpdateData Buffer\r
200   //\r
201   UpdateData = AllocateZeroPool (0x1000);\r
202   ASSERT (UpdateData != NULL);\r
203 \r
204   //\r
205   // Flag update pending in FormSet\r
206   //\r
207   UpdateData->FormSetUpdate = TRUE;\r
208   //\r
209   // Register CallbackHandle data for FormSet\r
210   //\r
211   UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) BootManagerCallbackHandle;\r
212   UpdateData->FormUpdate  = FALSE;\r
213   UpdateData->FormTitle   = 0;\r
214   UpdateData->DataCount   = 1;\r
215 \r
216   //\r
217   // Create blank space.  Since when we update the contents of IFR data at a label, it is\r
218   // inserted at the location of the label.  So if you want to add a string with an empty\r
219   // space afterwards, you need to add the space first and then the string like below.\r
220   //\r
221   Status = CreateSubTitleOpCode (\r
222             LastToken,        // Token Value for the string\r
223             &UpdateData->Data // Buffer containing created op-code\r
224             );\r
225 \r
226   Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
227 \r
228   //\r
229   // Create "Boot Option Menu" title\r
230   //\r
231   Status = CreateSubTitleOpCode (\r
232             STRING_TOKEN (STR_BOOT_OPTION_BANNER),  // Token Value for the string\r
233             &UpdateData->Data                       // Buffer containing created op-code\r
234             );\r
235 \r
236   Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
237 \r
238   Token                 = LastToken;\r
239   mKeyInput             = 0;\r
240 \r
241   UpdateData->DataCount = 0;\r
242   Location              = (UINT8 *) &UpdateData->Data;\r
243 \r
244   for (Link = BdsBootOptionList.ForwardLink; Link != &BdsBootOptionList; Link = Link->ForwardLink) {\r
245     Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
246 \r
247     //\r
248     // At this stage we are creating a menu entry, thus the Keys are reproduceable\r
249     //\r
250     mKeyInput++;\r
251     Token++;\r
252 \r
253     Status = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description);\r
254 \r
255     //\r
256     // If we got an error it is almost certainly due to the token value being invalid.\r
257     // Therefore we will set the Token to 0 to automatically add a token.\r
258     //\r
259     if (EFI_ERROR (Status)) {\r
260       Token   = 0;\r
261       Status  = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description);\r
262     }\r
263 \r
264     Status = CreateGotoOpCode (\r
265               0x1000, // Form ID\r
266               Token,  // Token Value for the string\r
267               0,      // Help String (none)\r
268               EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS,  // The Op-Code flags\r
269               mKeyInput,                                          // The Key to get a callback on\r
270               Location  // Buffer containing created op-code\r
271               );\r
272 \r
273     UpdateData->DataCount++;\r
274     Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length;\r
275 \r
276   }\r
277 \r
278   Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0001, TRUE, UpdateData);\r
279 \r
280   UpdateData->DataCount = 1;\r
281 \r
282   //\r
283   // Create "Boot Option Menu" title\r
284   //\r
285   Status = CreateSubTitleOpCode (\r
286             STRING_TOKEN (STR_HELP_FOOTER), // Token Value for the string\r
287             &UpdateData->Data               // Buffer containing created op-code\r
288             );\r
289 \r
290   Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData);\r
291 \r
292   Status = CreateSubTitleOpCode (\r
293             LastToken,                      // Token Value for the string\r
294             &UpdateData->Data               // Buffer containing created op-code\r
295             );\r
296 \r
297   Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData);\r
298 \r
299   gBS->FreePool (UpdateData);\r
300 \r
301   ASSERT (gBrowser);\r
302 \r
303   BootMngrMenuResetRequired = FALSE;\r
304   gBrowser->SendForm (\r
305               gBrowser, \r
306               TRUE, \r
307               &gBootManagerHandle, \r
308               1, \r
309               NULL, \r
310               NULL, \r
311               NULL, \r
312               NULL, \r
313               &BootMngrMenuResetRequired\r
314               );\r
315 \r
316   if (BootMngrMenuResetRequired) {\r
317     EnableResetRequired ();\r
318   }\r
319 \r
320   Hii->ResetStrings (Hii, gBootManagerHandle);\r
321 \r
322   if (gOption == NULL) {\r
323     return ;\r
324   }\r
325   \r
326   //\r
327   //Will leave browser, check any reset required change is applied? if yes, reset system\r
328   //\r
329   SetupResetReminder ();\r
330   \r
331   //\r
332   // BugBug: This code looks repeated from the BDS. Need to save code space.\r
333   //\r
334 \r
335   //\r
336   // parse the selected option\r
337   //\r
338   Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);\r
339 \r
340   if (!EFI_ERROR (Status)) {\r
341     PlatformBdsBootSuccess (gOption);\r
342   } else {\r
343     PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);\r
344     gST->ConOut->OutputString (\r
345                   gST->ConOut,\r
346                   GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))\r
347                   );\r
348 \r
349     //\r
350     // BdsLibUiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
351     //\r
352 \r
353     gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
354   }\r
355 }\r