]> code.delx.au - refind/blob - EfiLib/BdsTianoCore.c
Version 0.10.4 release.
[refind] / EfiLib / BdsTianoCore.c
1 /** @file
2 BDS Lib functions which relate with create or process the boot option.
3
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #ifdef __MAKEWITH_TIANO
16 #include "../include/tiano_includes.h"
17 #else
18 #include "BdsHelper.h"
19 #include "gnuefi-helper.h"
20 #endif
21 #include "../include/refit_call_wrapper.h"
22
23 EFI_GUID EfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
24
25 /**
26 This function will create all handles associate with every device
27 path node. If the handle associate with one device path node can not
28 be created success, then still give one chance to do the dispatch,
29 which load the missing drivers if possible.
30
31 @param DevicePathToConnect The device path which will be connected, it can be
32 a multi-instance device path
33
34 @retval EFI_SUCCESS All handles associate with every device path node
35 have been created
36 @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
37 @retval EFI_NOT_FOUND Create the handle associate with one device path
38 node failed
39
40 **/
41 EFI_STATUS
42 BdsLibConnectDevicePath (
43 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
44 )
45 {
46 EFI_STATUS Status;
47 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
48 EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
49 EFI_DEVICE_PATH_PROTOCOL *Instance;
50 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
51 EFI_DEVICE_PATH_PROTOCOL *Next;
52 EFI_HANDLE Handle;
53 EFI_HANDLE PreviousHandle;
54 UINTN Size;
55
56 if (DevicePathToConnect == NULL) {
57 return EFI_SUCCESS;
58 }
59
60 DevicePath = DuplicateDevicePath (DevicePathToConnect);
61 if (DevicePath == NULL) {
62 return EFI_OUT_OF_RESOURCES;
63 }
64 CopyOfDevicePath = DevicePath;
65
66 do {
67 //
68 // The outer loop handles multi instance device paths.
69 // Only console variables contain multiple instance device paths.
70 //
71 // After this call DevicePath points to the next Instance
72 //
73 Instance = GetNextDevicePathInstance (&DevicePath, &Size);
74 if (Instance == NULL) {
75 FreePool (CopyOfDevicePath);
76 return EFI_OUT_OF_RESOURCES;
77 }
78
79 Next = Instance;
80 while (!IsDevicePathEndType (Next)) {
81 Next = NextDevicePathNode (Next);
82 }
83
84 SetDevicePathEndNode (Next);
85
86 //
87 // Start the real work of connect with RemainingDevicePath
88 //
89 PreviousHandle = NULL;
90 do {
91 //
92 // Find the handle that best matches the Device Path. If it is only a
93 // partial match the remaining part of the device path is returned in
94 // RemainingDevicePath.
95 //
96 RemainingDevicePath = Instance;
97 Status = refit_call3_wrapper(gBS->LocateDevicePath, &EfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
98
99 if (!EFI_ERROR (Status)) {
100 #ifdef __MAKEWITH_TIANO
101 if (Handle == PreviousHandle) {
102 //
103 // If no forward progress is made try invoking the Dispatcher.
104 // A new FV may have been added to the system an new drivers
105 // may now be found.
106 // Status == EFI_SUCCESS means a driver was dispatched
107 // Status == EFI_NOT_FOUND means no new drivers were dispatched
108 //
109 Status = gDS->Dispatch ();
110 }
111 #endif
112
113 if (!EFI_ERROR (Status)) {
114 PreviousHandle = Handle;
115 //
116 // Connect all drivers that apply to Handle and RemainingDevicePath,
117 // the Recursive flag is FALSE so only one level will be expanded.
118 //
119 // Do not check the connect status here, if the connect controller fail,
120 // then still give the chance to do dispatch, because partial
121 // RemainingDevicepath may be in the new FV
122 //
123 // 1. If the connect fail, RemainingDevicepath and handle will not
124 // change, so next time will do the dispatch, then dispatch's status
125 // will take effect
126 // 2. If the connect success, the RemainingDevicepath and handle will
127 // change, then avoid the dispatch, we have chance to continue the
128 // next connection
129 //
130 refit_call4_wrapper(gBS->ConnectController, Handle, NULL, RemainingDevicePath, FALSE);
131 }
132 }
133 //
134 // Loop until RemainingDevicePath is an empty device path
135 //
136 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
137
138 } while (DevicePath != NULL);
139
140 if (CopyOfDevicePath != NULL) {
141 FreePool (CopyOfDevicePath);
142 }
143 //
144 // All handle with DevicePath exists in the handle database
145 //
146 return Status;
147 }
148
149 /**
150 Build the boot#### or driver#### option from the VariableName, the
151 build boot#### or driver#### will also be linked to BdsCommonOptionList.
152
153 @param BdsCommonOptionList The header of the boot#### or driver#### option
154 link list
155 @param VariableName EFI Variable name indicate if it is boot#### or
156 driver####
157
158 @retval BDS_COMMON_OPTION Get the option just been created
159 @retval NULL Failed to get the new option
160
161 **/
162 BDS_COMMON_OPTION *
163 BdsLibVariableToOption (
164 IN OUT LIST_ENTRY *BdsCommonOptionList,
165 IN CHAR16 *VariableName
166 )
167 {
168 UINT32 Attribute;
169 UINT16 FilePathSize;
170 UINT8 *Variable;
171 UINT8 *TempPtr;
172 UINTN VariableSize;
173 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
174 BDS_COMMON_OPTION *Option;
175 VOID *LoadOptions;
176 UINT32 LoadOptionsSize;
177 CHAR16 *Description;
178 UINT8 NumOff;
179 EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
180
181 //
182 // Read the variable. We will never free this data.
183 //
184 Variable = BdsLibGetVariableAndSize (
185 VariableName,
186 &EfiGlobalVariableGuid,
187 &VariableSize
188 );
189 if (Variable == NULL) {
190 return NULL;
191 }
192 //
193 // Notes: careful defined the variable of Boot#### or
194 // Driver####, consider use some macro to abstract the code
195 //
196 //
197 // Get the option attribute
198 //
199 TempPtr = Variable;
200 Attribute = *(UINT32 *) Variable;
201 TempPtr += sizeof (UINT32);
202
203 //
204 // Get the option's device path size
205 //
206 FilePathSize = *(UINT16 *) TempPtr;
207 TempPtr += sizeof (UINT16);
208
209 //
210 // Get the option's description string
211 //
212 Description = (CHAR16 *) TempPtr;
213
214 //
215 // Get the option's description string size
216 //
217 TempPtr += StrSize ((CHAR16 *) TempPtr);
218
219 //
220 // Get the option's device path
221 //
222 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
223 TempPtr += FilePathSize;
224
225 LoadOptions = TempPtr;
226 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
227
228 //
229 // The Console variables may have multiple device paths, so make
230 // an Entry for each one.
231 //
232 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
233 if (Option == NULL) {
234 return NULL;
235 }
236
237 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
238 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
239 ASSERT(Option->DevicePath != NULL);
240 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
241
242 Option->Attribute = Attribute;
243 Option->Description = AllocateZeroPool (StrSize (Description));
244 ASSERT(Option->Description != NULL);
245 CopyMem (Option->Description, Description, StrSize (Description));
246
247 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
248 ASSERT(Option->LoadOptions != NULL);
249 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
250 Option->LoadOptionsSize = LoadOptionsSize;
251
252 //
253 // Get the value from VariableName Unicode string
254 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
255 // Unicode stream to ASCII without any loss in meaning.
256 //
257 if (*VariableName == 'B') {
258 NumOff = (UINT8) (sizeof (L"Boot") / sizeof(CHAR16) - 1);
259 Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000);
260 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100));
261 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10));
262 Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0')));
263 }
264 //
265 // Insert active entry to BdsDeviceList
266 //
267 if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
268 InsertTailList (BdsCommonOptionList, &Option->Link);
269 FreePool (Variable);
270 return Option;
271 }
272
273 FreePool (Variable);
274 FreePool (Option);
275 return NULL;
276
277 }
278
279
280 /**
281 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
282 buffer, and the size of the buffer. If failure return NULL.
283
284 @param Name String part of EFI variable name
285 @param VendorGuid GUID part of EFI variable name
286 @param VariableSize Returns the size of the EFI variable that was read
287
288 @return Dynamically allocated memory that contains a copy of the EFI variable
289 Caller is responsible freeing the buffer.
290 @retval NULL Variable was not read
291
292 **/
293 VOID *
294 BdsLibGetVariableAndSize (
295 IN CHAR16 *Name,
296 IN EFI_GUID *VendorGuid,
297 OUT UINTN *VariableSize
298 )
299 {
300 EFI_STATUS Status;
301 UINTN BufferSize;
302 VOID *Buffer;
303
304 Buffer = NULL;
305
306 //
307 // Pass in a zero size buffer to find the required buffer size.
308 //
309 BufferSize = 0;
310 Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer);
311 if (Status == EFI_BUFFER_TOO_SMALL) {
312 //
313 // Allocate the buffer to return
314 //
315 Buffer = AllocateZeroPool (BufferSize);
316 if (Buffer == NULL) {
317 return NULL;
318 }
319 //
320 // Read variable into the allocated buffer.
321 //
322 Status = refit_call5_wrapper(gRT->GetVariable, Name, VendorGuid, NULL, &BufferSize, Buffer);
323 if (EFI_ERROR (Status)) {
324 BufferSize = 0;
325 }
326 }
327
328 *VariableSize = BufferSize;
329 return Buffer;
330 }
331