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