]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/BdsLib/BdsLoadOption.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsLoadOption.c
CommitLineData
1e57a462 1/** @file\r
2*\r
3* Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
17EFI_STATUS\r
18BootOptionParseLoadOption (\r
19 IN EFI_LOAD_OPTION EfiLoadOption,\r
20 IN UINTN EfiLoadOptionSize,\r
21 IN OUT BDS_LOAD_OPTION **BdsLoadOption\r
22 )\r
23{\r
24 BDS_LOAD_OPTION *LoadOption;\r
25 UINTN DescriptionLength;\r
26\r
27 if (EfiLoadOption == NULL) {\r
28 return EFI_INVALID_PARAMETER;\r
29 }\r
30\r
31 if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {\r
32 return EFI_BAD_BUFFER_SIZE;\r
33 }\r
34\r
35 if (*BdsLoadOption == NULL) {\r
36 LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));\r
37 if (LoadOption == NULL) {\r
38 return EFI_OUT_OF_RESOURCES;\r
39 }\r
40 } else {\r
41 LoadOption = *BdsLoadOption;\r
42 }\r
43\r
44 LoadOption->LoadOption = EfiLoadOption;\r
45 LoadOption->LoadOptionSize = EfiLoadOptionSize;\r
46\r
47 LoadOption->Attributes = *(UINT32*)EfiLoadOption;\r
48 LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));\r
49 LoadOption->Description = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));\r
50 DescriptionLength = StrSize (LoadOption->Description);\r
51 LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);\r
52\r
53 // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data\r
54 if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - (UINTN)EfiLoadOption) == EfiLoadOptionSize) {\r
55 LoadOption->OptionalData = NULL;\r
56 LoadOption->OptionalDataSize = 0;\r
57 } else {\r
58 LoadOption->OptionalData = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);\r
59 LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - (UINTN)EfiLoadOption);\r
60 }\r
61\r
62 if (*BdsLoadOption == NULL) {\r
63 *BdsLoadOption = LoadOption;\r
64 }\r
65\r
66 return EFI_SUCCESS;\r
67}\r
68\r
69EFI_STATUS\r
70BootOptionFromLoadOptionVariable (\r
71 IN CHAR16* BootVariableName,\r
72 OUT BDS_LOAD_OPTION** BdsLoadOption\r
73 )\r
74{\r
75 EFI_STATUS Status;\r
76 EFI_LOAD_OPTION EfiLoadOption;\r
77 UINTN EfiLoadOptionSize;\r
78\r
79 Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);\r
80 if (!EFI_ERROR(Status)) {\r
81 *BdsLoadOption = NULL;\r
82 Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption);\r
83 }\r
84\r
85 return Status;\r
86}\r
87\r
88EFI_STATUS\r
89BootOptionFromLoadOptionIndex (\r
90 IN UINT16 LoadOptionIndex,\r
91 OUT BDS_LOAD_OPTION **BdsLoadOption\r
92 )\r
93{\r
94 CHAR16 BootVariableName[9];\r
95 EFI_STATUS Status;\r
96\r
97 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);\r
98\r
99 Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption);\r
100 if (!EFI_ERROR(Status)) {\r
101 (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;\r
102 }\r
103\r
104 return Status;\r
105}\r
106\r
107EFI_STATUS\r
108BootOptionToLoadOptionVariable (\r
109 IN BDS_LOAD_OPTION* BdsLoadOption\r
110 )\r
111{\r
112 EFI_STATUS Status;\r
113 UINTN DescriptionSize;\r
114 //UINT16 FilePathListLength;\r
115 EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;\r
116 UINTN NodeLength;\r
117 UINT8* EfiLoadOptionPtr;\r
118 VOID* OldLoadOption;\r
119 CHAR16 BootVariableName[9];\r
120 UINTN BootOrderSize;\r
121 UINT16* BootOrder;\r
122\r
123 // If we are overwriting an existent Boot Option then we have to free previously allocated memory\r
124 if (BdsLoadOption->LoadOptionSize > 0) {\r
125 OldLoadOption = BdsLoadOption->LoadOption;\r
126 } else {\r
127 OldLoadOption = NULL;\r
128\r
129 // If this function is called at the creation of the Boot Device entry (not at the update) the\r
130 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry\r
131 BdsLoadOption->LoadOptionIndex = BootOptionAllocateBootIndex ();\r
132\r
133 //TODO: Add to the the Boot Entry List\r
134 }\r
135\r
136 DescriptionSize = StrSize(BdsLoadOption->Description);\r
137\r
138 // Ensure the FilePathListLength information is correct\r
139 ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength);\r
140\r
141 // Allocate the memory for the EFI Load Option\r
142 BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;\r
143\r
144 BdsLoadOption->LoadOption = (EFI_LOAD_OPTION)AllocateZeroPool (BdsLoadOption->LoadOptionSize);\r
145 if (BdsLoadOption->LoadOption == NULL) {\r
146 return EFI_OUT_OF_RESOURCES;\r
147 }\r
148\r
149 EfiLoadOptionPtr = BdsLoadOption->LoadOption;\r
150\r
151 //\r
152 // Populate the EFI Load Option and BDS Boot Option structures\r
153 //\r
154\r
155 // Attributes fields\r
156 *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;\r
157 EfiLoadOptionPtr += sizeof(UINT32);\r
158\r
159 // FilePath List fields\r
160 *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;\r
161 EfiLoadOptionPtr += sizeof(UINT16);\r
162\r
163 // Boot description fields\r
164 CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);\r
165 EfiLoadOptionPtr += DescriptionSize;\r
166\r
167 // File path fields\r
168 DevicePathNode = BdsLoadOption->FilePathList;\r
169 while (!IsDevicePathEndType (DevicePathNode)) {\r
170 NodeLength = DevicePathNodeLength(DevicePathNode);\r
171 CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);\r
172 EfiLoadOptionPtr += NodeLength;\r
173 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
174 }\r
175\r
176 // Set the End Device Path Type\r
177 SetDevicePathEndNode (EfiLoadOptionPtr);\r
178 EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);\r
179\r
180 // Fill the Optional Data\r
181 if (BdsLoadOption->OptionalDataSize > 0) {\r
182 CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);\r
183 }\r
184\r
185 // Case where the fields have been updated\r
186 if (OldLoadOption) {\r
187 // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption\r
188 BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->LoadOptionSize, &BdsLoadOption);\r
189 // Free the old packed structure\r
190 FreePool (OldLoadOption);\r
191 }\r
192\r
193 // Create/Update Boot#### environment variable\r
194 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);\r
195 Status = gRT->SetVariable (\r
196 BootVariableName,\r
197 &gEfiGlobalVariableGuid,\r
198 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
199 BdsLoadOption->LoadOptionSize,\r
200 BdsLoadOption->LoadOption\r
201 );\r
202\r
203 // When it is a new entry we must add the entry to the BootOrder\r
204 if (OldLoadOption == NULL) {\r
205 // Add the new Boot Index to the list\r
206 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
207 if (!EFI_ERROR(Status)) {\r
208 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);\r
209 // Add the new index at the end\r
210 BootOrder[BootOrderSize / sizeof(UINT16)] = BdsLoadOption->LoadOptionIndex;\r
211 BootOrderSize += sizeof(UINT16);\r
212 } else {\r
213 // BootOrder does not exist. Create it\r
214 BootOrderSize = sizeof(UINT16);\r
215 BootOrder = &(BdsLoadOption->LoadOptionIndex);\r
216 }\r
217\r
218 // Update (or Create) the BootOrder environment variable\r
219 gRT->SetVariable (\r
220 L"BootOrder",\r
221 &gEfiGlobalVariableGuid,\r
222 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
223 BootOrderSize,\r
224 BootOrder\r
225 );\r
226 DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName));\r
227\r
228 // Free memory allocated by GetEnvironmentVariable\r
229 if (!EFI_ERROR(Status)) {\r
230 FreePool (BootOrder);\r
231 }\r
232 } else {\r
233 DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName));\r
234 }\r
235\r
236 return EFI_SUCCESS;\r
237}\r
238\r
239UINT16\r
240BootOptionAllocateBootIndex (\r
241 VOID\r
242 )\r
243{\r
244 EFI_STATUS Status;\r
245 UINTN Index;\r
246 UINT32 BootIndex;\r
247 UINT16 *BootOrder;\r
248 UINTN BootOrderSize;\r
249 BOOLEAN Found;\r
250\r
251 // Get the Boot Option Order from the environment variable\r
252 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
253 if (!EFI_ERROR(Status)) {\r
254 for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {\r
255 Found = FALSE;\r
256 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
257 if (BootOrder[Index] == BootIndex) {\r
258 Found = TRUE;\r
259 break;\r
260 }\r
261 }\r
262 if (!Found) {\r
263 return BootIndex;\r
264 }\r
265 }\r
266 FreePool (BootOrder);\r
267 }\r
268 // Return the first index\r
269 return 0;\r
270}\r