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