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