]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Application/LinuxLoader/LinuxConfig.c
ArmPkg: Introduce GetGlobalEnvironmentVariable() function.
[mirror_edk2.git] / ArmPkg / Application / LinuxLoader / LinuxConfig.c
CommitLineData
1e57a462 1/** @file\r
2*\r
c0b2e477 3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
1e57a462 4*\r
c0b2e477 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
1e57a462 12*\r
13**/\r
14\r
15#include "LinuxInternal.h"\r
16\r
17#define DEFAULT_BOOT_ENTRY_DESCRIPTION L"Linux"\r
18#define MAX_STR_INPUT 300\r
19#define MAX_ASCII_INPUT 300\r
20\r
21typedef enum {\r
22 LINUX_LOADER_NEW = 1,\r
23 LINUX_LOADER_UPDATE\r
24} LINUX_LOADER_ACTION;\r
25\r
26STATIC\r
27EFI_STATUS\r
28EditHIInputStr (\r
29 IN OUT CHAR16 *CmdLine,\r
30 IN UINTN MaxCmdLine\r
31 )\r
32{\r
33 UINTN CmdLineIndex;\r
34 UINTN WaitIndex;\r
35 CHAR8 Char;\r
36 EFI_INPUT_KEY Key;\r
37 EFI_STATUS Status;\r
38\r
39 Print (CmdLine);\r
40\r
41 for (CmdLineIndex = StrLen (CmdLine); CmdLineIndex < MaxCmdLine; ) {\r
42 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);\r
43 ASSERT_EFI_ERROR (Status);\r
44\r
45 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
46 ASSERT_EFI_ERROR (Status);\r
47\r
48 // Unicode character is valid when Scancode is NUll\r
49 if (Key.ScanCode == SCAN_NULL) {\r
50 // Scan code is NUll, hence read Unicode character\r
51 Char = (CHAR8)Key.UnicodeChar;\r
52 } else {\r
53 Char = CHAR_NULL;\r
54 }\r
55\r
56 if ((Char == CHAR_LINEFEED) || (Char == CHAR_CARRIAGE_RETURN) || (Char == 0x7f)) {\r
57 CmdLine[CmdLineIndex] = '\0';\r
58 Print (L"\n\r");\r
59\r
60 return EFI_SUCCESS;\r
61 } else if ((Key.UnicodeChar == L'\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){\r
62 if (CmdLineIndex != 0) {\r
63 CmdLineIndex--;\r
64 Print (L"\b \b");\r
65 }\r
66 } else if ((Key.ScanCode == SCAN_ESC) || (Char == 0x1B) || (Char == 0x0)) {\r
67 return EFI_INVALID_PARAMETER;\r
68 } else {\r
69 CmdLine[CmdLineIndex++] = Key.UnicodeChar;\r
70 Print (L"%c", Key.UnicodeChar);\r
71 }\r
72 }\r
73\r
74 return EFI_SUCCESS;\r
75}\r
76\r
77STATIC\r
78EFI_STATUS\r
79EditHIInputAscii (\r
80 IN OUT CHAR8 *CmdLine,\r
81 IN UINTN MaxCmdLine\r
82 )\r
83{\r
84 CHAR16* Str;\r
85 EFI_STATUS Status;\r
86\r
87 Str = (CHAR16*)AllocatePool (MaxCmdLine * sizeof(CHAR16));\r
88 AsciiStrToUnicodeStr (CmdLine, Str);\r
89\r
90 Status = EditHIInputStr (Str, MaxCmdLine);\r
91\r
92 UnicodeStrToAsciiStr (Str, CmdLine);\r
93 FreePool (Str);\r
94\r
95 return Status;\r
96}\r
97\r
98STATIC\r
99EFI_STATUS\r
100GetHIInputInteger (\r
101 OUT UINTN *Integer\r
102 )\r
103{\r
104 CHAR16 CmdLine[255];\r
105 EFI_STATUS Status;\r
106\r
107 CmdLine[0] = '\0';\r
108 Status = EditHIInputStr (CmdLine, 255);\r
109 if (!EFI_ERROR(Status)) {\r
110 *Integer = StrDecimalToUintn (CmdLine);\r
111 }\r
112\r
113 return Status;\r
114}\r
115\r
116#if 0\r
117EFI_STATUS\r
118GenerateDeviceDescriptionName (\r
119 IN EFI_HANDLE Handle,\r
120 IN OUT CHAR16* Description\r
121 )\r
122{\r
123 EFI_STATUS Status;\r
124 EFI_COMPONENT_NAME_PROTOCOL* ComponentName2Protocol;\r
125 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
126 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
127 CHAR16* DriverName;\r
128 CHAR16* DevicePathTxt;\r
129 EFI_DEVICE_PATH* DevicePathNode;\r
130\r
131 ComponentName2Protocol = NULL;\r
132 Status = gBS->HandleProtocol (Handle, &gEfiComponentName2ProtocolGuid, (VOID **)&ComponentName2Protocol);\r
133 if (!EFI_ERROR(Status)) {\r
134 //TODO: Fixme. we must find the best langague\r
135 Status = ComponentName2Protocol->GetDriverName (ComponentName2Protocol,"en",&DriverName);\r
136 if (!EFI_ERROR(Status)) {\r
137 StrnCpy (Description,DriverName,BOOT_DEVICE_DESCRIPTION_MAX);\r
138 }\r
139 }\r
140\r
141 if (EFI_ERROR(Status)) {\r
142 // Use the lastest non null entry of the Device path as a description\r
143 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
144 if (EFI_ERROR(Status)) {\r
145 return Status;\r
146 }\r
147\r
148 // Convert the last non end-type Device Path Node in text for the description\r
149 DevicePathNode = GetLastDevicePathNode (DevicePathProtocol);\r
150 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
151 ASSERT_EFI_ERROR(Status);\r
152 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(DevicePathNode,TRUE,TRUE);\r
153 StrnCpy (Description, DevicePathTxt, BOOT_DEVICE_DESCRIPTION_MAX);\r
154 FreePool (DevicePathTxt);\r
155 }\r
156\r
157 return EFI_SUCCESS;\r
158}\r
159#endif\r
160\r
161EFI_STATUS\r
162LinuxLoaderConfig (\r
163 IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage\r
164 )\r
165{\r
166 EFI_STATUS Status;\r
167 LINUX_LOADER_ACTION Choice;\r
168 UINTN BootOrderSize;\r
169 UINT16* BootOrder;\r
170 UINTN BootOrderCount;\r
171 UINTN Index;\r
172 CHAR16 Description[MAX_ASCII_INPUT];\r
173 CHAR8 CmdLine[MAX_ASCII_INPUT];\r
174 CHAR16 Initrd[MAX_STR_INPUT];\r
175 UINT16 InitrdPathListLength;\r
176 UINT16 CmdLineLength;\r
177 BDS_LOAD_OPTION* BdsLoadOption;\r
178 BDS_LOAD_OPTION** SupportedBdsLoadOptions;\r
179 UINTN SupportedBdsLoadOptionCount;\r
180 LINUX_LOADER_OPTIONAL_DATA* LinuxOptionalData;\r
181 EFI_DEVICE_PATH* DevicePathRoot;\r
182\r
3eef284c 183 Choice = (LINUX_LOADER_ACTION)0;\r
1e57a462 184 SupportedBdsLoadOptions = NULL;\r
185 SupportedBdsLoadOptionCount = 0;\r
186\r
187 do {\r
188 Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW);\r
189 Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE);\r
190\r
191 Print (L"Option: ");\r
192 Status = GetHIInputInteger (&Choice);\r
193 if (Status == EFI_INVALID_PARAMETER) {\r
194 Print (L"\n");\r
195 return Status;\r
196 } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) {\r
197 Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE);\r
198 Status = EFI_INVALID_PARAMETER;\r
199 }\r
200 } while (EFI_ERROR(Status));\r
201\r
202 if (Choice == LINUX_LOADER_UPDATE) {\r
203 // If no compatible entry then we just create a new entry\r
204 Choice = LINUX_LOADER_NEW;\r
205\r
206 // Scan the OptionalData of every entry for the correct signature\r
c0b2e477 207 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
1e57a462 208 if (!EFI_ERROR(Status)) {\r
209 BootOrderCount = BootOrderSize / sizeof(UINT16);\r
210\r
211 // Allocate an array to handle maximum number of supported Boot Entry\r
212 SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount);\r
213\r
214 SupportedBdsLoadOptionCount = 0;\r
215\r
216 // Check if the signature is present in the list of the current Boot entries\r
217 for (Index = 0; Index < BootOrderCount; Index++) {\r
218 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);\r
219 if (!EFI_ERROR(Status)) {\r
220 if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) &&\r
221 (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) {\r
222 SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption;\r
223 Choice = LINUX_LOADER_UPDATE;\r
224 }\r
225 }\r
226 }\r
227 }\r
228 FreePool (BootOrder);\r
229 }\r
230\r
231 if (Choice == LINUX_LOADER_NEW) {\r
232 Description[0] = '\0';\r
233 CmdLine[0] = '\0';\r
234 Initrd[0] = '\0';\r
235\r
236 BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));\r
237\r
238 DEBUG_CODE_BEGIN();\r
239 CHAR16* DevicePathTxt;\r
240 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
241\r
242 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
243 ASSERT_EFI_ERROR(Status);\r
244 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);\r
245\r
246 Print(L"EFI OS Loader: %s\n",DevicePathTxt);\r
247\r
248 FreePool(DevicePathTxt);\r
249 DEBUG_CODE_END();\r
250\r
251 //\r
252 // Fill the known fields of BdsLoadOption\r
253 //\r
254\r
255 BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;\r
256\r
257 // Get the full Device Path for this file\r
258 Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot);\r
259 ASSERT_EFI_ERROR(Status);\r
260\r
261 BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath);\r
262 BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);\r
263 } else {\r
264 if (SupportedBdsLoadOptionCount > 1) {\r
265 for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) {\r
266 Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description);\r
267 }\r
268\r
269 do {\r
270 Print (L"Update Boot Entry: ");\r
271 Status = GetHIInputInteger (&Choice);\r
272 if (Status == EFI_INVALID_PARAMETER) {\r
273 Print (L"\n");\r
274 return Status;\r
275 } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) {\r
276 Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount);\r
277 Status = EFI_INVALID_PARAMETER;\r
278 }\r
279 } while (EFI_ERROR(Status));\r
280 BdsLoadOption = SupportedBdsLoadOptions[Choice-1];\r
281 }\r
282 StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT);\r
283\r
284 LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData;\r
285 if (LinuxOptionalData->CmdLineLength > 0) {\r
286 CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength);\r
287 } else {\r
288 CmdLine[0] = '\0';\r
289 }\r
290\r
291 if (LinuxOptionalData->InitrdPathListLength > 0) {\r
292 CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength);\r
293 } else {\r
294 Initrd[0] = L'\0';\r
295 }\r
296 DEBUG((EFI_D_ERROR,"L\n"));\r
297 }\r
298\r
299 // Description\r
300 Print (L"Description: ");\r
301 Status = EditHIInputStr (Description, MAX_STR_INPUT);\r
302 if (EFI_ERROR(Status)) {\r
303 return Status;\r
304 }\r
305 if (StrLen (Description) == 0) {\r
306 StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT);\r
307 }\r
308 BdsLoadOption->Description = Description;\r
309\r
310 // CmdLine\r
311 Print (L"Command Line: ");\r
312 Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT);\r
313 if (EFI_ERROR(Status)) {\r
314 return Status;\r
315 }\r
316\r
317 // Initrd\r
318 Print (L"Initrd name: ");\r
319 Status = EditHIInputStr (Initrd, MAX_STR_INPUT);\r
320 if (EFI_ERROR(Status)) {\r
321 return Status;\r
322 }\r
323\r
324 CmdLineLength = AsciiStrLen (CmdLine);\r
325 if (CmdLineLength > 0) {\r
326 CmdLineLength += sizeof(CHAR8);\r
327 }\r
328\r
329 InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16);\r
330 if (InitrdPathListLength > 0) {\r
331 InitrdPathListLength += sizeof(CHAR16);\r
332 }\r
333\r
334 BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength;\r
335\r
336 LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize);\r
337 BdsLoadOption->OptionalData = LinuxOptionalData;\r
338\r
339 LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE;\r
340 LinuxOptionalData->CmdLineLength = CmdLineLength;\r
341 LinuxOptionalData->InitrdPathListLength = InitrdPathListLength;\r
342\r
343 if (CmdLineLength > 0) {\r
344 CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength);\r
345 }\r
346 if (InitrdPathListLength > 0) {\r
347 CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength);\r
348 }\r
349\r
350 // Create or Update the boot entry\r
351 Status = BootOptionToLoadOptionVariable (BdsLoadOption);\r
352\r
353 return Status;\r
354}\r