a52b11653800c5b26fa85131395fee8cd10f1421
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / PlatformBds / Generic / BdsEntry.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   BdsEntry.c\r
15 \r
16 Abstract:\r
17 \r
18   The entry of the bds\r
19 \r
20 --*/\r
21 \r
22 #include "Bds.h"\r
23 #include "BdsPlatform.h"\r
24 #include "FrontPage.h"\r
25 \r
26 EFI_BDS_ARCH_PROTOCOL_INSTANCE  gBdsInstanceTemplate = {\r
27   EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE,\r
28   NULL,\r
29   {\r
30     BdsEntry\r
31   },\r
32   0xFFFF,\r
33   TRUE,\r
34   EXTENSIVE\r
35 };\r
36 \r
37 UINT16                          *mBootNext = NULL;\r
38 \r
39 EFI_HANDLE                      mBdsImageHandle;\r
40 \r
41 EFI_STATUS\r
42 EFIAPI\r
43 BdsInitialize (\r
44   IN EFI_HANDLE                            ImageHandle,\r
45   IN EFI_SYSTEM_TABLE                      *SystemTable\r
46   )\r
47 /*++\r
48 \r
49 Routine Description:\r
50 \r
51   Install Boot Device Selection Protocol\r
52 \r
53 Arguments:\r
54   \r
55   (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
56 \r
57 Returns:\r
58 \r
59   EFI_SUCEESS - BDS has finished initializing.\r
60                 Rerun the \r
61                 dispatcher and recall BDS.Entry\r
62 \r
63   Other       - Return value from EfiLibAllocatePool()\r
64                 or gBS->InstallProtocolInterface\r
65 \r
66 --*/\r
67 {\r
68   EFI_STATUS  Status;\r
69 \r
70   mBdsImageHandle = ImageHandle;\r
71 \r
72   //\r
73   // Install protocol interface\r
74   //\r
75   Status = gBS->InstallProtocolInterface (\r
76                   &gBdsInstanceTemplate.Handle,\r
77                   &gEfiBdsArchProtocolGuid,\r
78                   EFI_NATIVE_INTERFACE,\r
79                   &gBdsInstanceTemplate.Bds\r
80                   );\r
81   ASSERT_EFI_ERROR (Status);\r
82 \r
83   return Status;\r
84 }\r
85 \r
86 VOID\r
87 BdsBootDeviceSelect (\r
88   VOID\r
89   )\r
90 /*++\r
91 \r
92 Routine Description:\r
93 \r
94   In the loop of attempt to boot for the boot order\r
95 \r
96 Arguments:\r
97   \r
98   None.\r
99 \r
100 Returns:\r
101 \r
102   None.\r
103   \r
104 --*/\r
105 {\r
106   EFI_STATUS        Status;\r
107   LIST_ENTRY        *Link;\r
108   BDS_COMMON_OPTION *BootOption;\r
109   UINTN             ExitDataSize;\r
110   CHAR16            *ExitData;\r
111   UINT16            Timeout;\r
112   LIST_ENTRY        BootLists;\r
113   CHAR16            Buffer[20];\r
114   BOOLEAN           BootNextExist;\r
115   LIST_ENTRY        *LinkBootNext;\r
116 \r
117   //\r
118   // Got the latest boot option\r
119   //\r
120   BootNextExist = FALSE;\r
121   LinkBootNext  = NULL;\r
122   InitializeListHead (&BootLists);\r
123 \r
124   //\r
125   // First check the boot next option\r
126   //\r
127   ZeroMem (Buffer, sizeof (Buffer));\r
128 \r
129   if (mBootNext != NULL) {\r
130     //\r
131     // Indicate we have the boot next variable, so this time\r
132     // boot will always have this boot option\r
133     //\r
134     BootNextExist = TRUE;\r
135 \r
136     //\r
137     // Clear the this variable so it's only exist in this time boot\r
138     //\r
139     gRT->SetVariable (\r
140           L"BootNext",\r
141           &gEfiGlobalVariableGuid,\r
142           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
143           0,\r
144           mBootNext\r
145           );\r
146 \r
147     //\r
148     // Add the boot next boot option\r
149     //\r
150     UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
151     BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
152   }\r
153   //\r
154   // Parse the boot order to get boot option\r
155   //\r
156   BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
157   Link = BootLists.ForwardLink;\r
158 \r
159   //\r
160   // Parameter check, make sure the loop will be valid\r
161   //\r
162   if (Link == NULL) {\r
163     return ;\r
164   }\r
165   //\r
166   // Here we make the boot in a loop, every boot success will\r
167   // return to the front page\r
168   //\r
169   for (;;) {\r
170     //\r
171     // Check the boot option list first\r
172     //\r
173     if (Link == &BootLists) {\r
174       //\r
175       // There are two ways to enter here:\r
176       // 1. There is no active boot option, give user chance to\r
177       //    add new boot option\r
178       // 2. All the active boot option processed, and there is no\r
179       //    one is success to boot, then we back here to allow user\r
180       //    add new active boot option\r
181       //\r
182       Timeout = 0xffff;\r
183       PlatformBdsEnterFrontPage (Timeout, FALSE);\r
184       InitializeListHead (&BootLists);\r
185       BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
186       Link = BootLists.ForwardLink;\r
187       continue;\r
188     }\r
189     //\r
190     // Get the boot option from the link list\r
191     //\r
192     BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
193 \r
194     //\r
195     // According to EFI Specification, if a load option is not marked\r
196     // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
197     // load the option.\r
198     //\r
199     if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
200       //\r
201       // skip the header of the link list, becuase it has no boot option\r
202       //\r
203       Link = Link->ForwardLink;\r
204       continue;\r
205     }\r
206     //\r
207     // Make sure the boot option device path connected,\r
208     // but ignore the BBS device path\r
209     //\r
210     if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
211       //\r
212       // Notes: the internal shell can not been connected with device path\r
213       // so we do not check the status here\r
214       //\r
215       BdsLibConnectDevicePath (BootOption->DevicePath);\r
216     }\r
217     //\r
218     // All the driver options should have been processed since\r
219     // now boot will be performed.\r
220     //\r
221     PERF_END (0, BDS_TOK, NULL, 0);\r
222     Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
223     if (EFI_ERROR (Status)) {\r
224       //\r
225       // Call platform action to indicate the boot fail\r
226       //\r
227       PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
228 \r
229       //\r
230       // Check the next boot option\r
231       //\r
232       Link = Link->ForwardLink;\r
233 \r
234     } else {\r
235       //\r
236       // Call platform action to indicate the boot success\r
237       //\r
238       PlatformBdsBootSuccess (BootOption);\r
239 \r
240       //\r
241       // Boot success, then stop process the boot order, and\r
242       // present the boot manager menu, front page\r
243       //\r
244       Timeout = 0xffff;\r
245       PlatformBdsEnterFrontPage (Timeout, FALSE);\r
246 \r
247       //\r
248       // Rescan the boot option list, avoid pertential risk of the boot\r
249       // option change in front page\r
250       //\r
251       if (BootNextExist) {\r
252         LinkBootNext = BootLists.ForwardLink;\r
253       }\r
254 \r
255       InitializeListHead (&BootLists);\r
256       if (LinkBootNext != NULL) {\r
257         //\r
258         // Reserve the boot next option\r
259         //\r
260         InsertTailList (&BootLists, LinkBootNext);\r
261       }\r
262 \r
263       BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
264       Link = BootLists.ForwardLink;\r
265     }\r
266   }\r
267 \r
268   return ;\r
269 \r
270 }\r
271 \r
272 VOID\r
273 EFIAPI\r
274 BdsEntry (\r
275   IN EFI_BDS_ARCH_PROTOCOL  *This\r
276   )\r
277 /*++\r
278 \r
279 Routine Description:\r
280 \r
281   Service routine for BdsInstance->Entry(). Devices are connected, the \r
282   consoles are initialized, and the boot options are tried. \r
283 \r
284 Arguments:\r
285 \r
286   This - Protocol Instance structure.\r
287 \r
288 Returns:\r
289 \r
290   EFI_SUCEESS - BDS->Entry has finished executing. \r
291                 \r
292 --*/\r
293 {\r
294   EFI_BDS_ARCH_PROTOCOL_INSTANCE  *PrivateData;\r
295   LIST_ENTRY                      DriverOptionList;\r
296   LIST_ENTRY                      BootOptionList;\r
297   UINTN                           BootNextSize;\r
298 \r
299   //\r
300   // Insert the performance probe\r
301   //\r
302   PERF_END (0, DXE_TOK, NULL, 0);\r
303   PERF_START (0, BDS_TOK, NULL, 0);\r
304 \r
305   //\r
306   // Initialize the global system boot option and driver option\r
307   //\r
308   InitializeListHead (&DriverOptionList);\r
309   InitializeListHead (&BootOptionList);\r
310 \r
311   //\r
312   // Get the BDS private data\r
313   //\r
314   PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This);\r
315 \r
316   //\r
317   // Do the platform init, can be customized by OEM/IBV\r
318   //\r
319   PERF_START (0, "PlatformBds", "BDS", 0);\r
320   PlatformBdsInit (PrivateData);\r
321 \r
322   //\r
323   // Set up the device list based on EFI 1.1 variables\r
324   // process Driver#### and Load the driver's in the\r
325   // driver option list\r
326   //\r
327   BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
328   if (!IsListEmpty (&DriverOptionList)) {\r
329     BdsLibLoadDrivers (&DriverOptionList);\r
330   }\r
331   //\r
332   // Check if we have the boot next option\r
333   //\r
334   mBootNext = BdsLibGetVariableAndSize (\r
335                 L"BootNext",\r
336                 &gEfiGlobalVariableGuid,\r
337                 &BootNextSize\r
338                 );\r
339 \r
340   //\r
341   // Setup some platform policy here\r
342   //\r
343   PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList);\r
344   PERF_END (0, "PlatformBds", "BDS", 0);\r
345 \r
346   //\r
347   // BDS select the boot device to load OS\r
348   //\r
349   BdsBootDeviceSelect ();\r
350 \r
351   //\r
352   // Only assert here since this is the right behavior, we should never\r
353   // return back to DxeCore.\r
354   //\r
355   ASSERT (FALSE);\r
356 }\r
357 \r