]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Application/LinuxLoader/LinuxConfig.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPkg / Application / LinuxLoader / LinuxConfig.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 "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
183 SupportedBdsLoadOptions = NULL;\r
184 SupportedBdsLoadOptionCount = 0;\r
185\r
186 do {\r
187 Print (L"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW);\r
188 Print (L"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE);\r
189\r
190 Print (L"Option: ");\r
191 Status = GetHIInputInteger (&Choice);\r
192 if (Status == EFI_INVALID_PARAMETER) {\r
193 Print (L"\n");\r
194 return Status;\r
195 } else if ((Choice != LINUX_LOADER_NEW) && (Choice != LINUX_LOADER_UPDATE)) {\r
196 Print (L"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW,LINUX_LOADER_UPDATE);\r
197 Status = EFI_INVALID_PARAMETER;\r
198 }\r
199 } while (EFI_ERROR(Status));\r
200\r
201 if (Choice == LINUX_LOADER_UPDATE) {\r
202 // If no compatible entry then we just create a new entry\r
203 Choice = LINUX_LOADER_NEW;\r
204\r
205 // Scan the OptionalData of every entry for the correct signature\r
206 Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
207 if (!EFI_ERROR(Status)) {\r
208 BootOrderCount = BootOrderSize / sizeof(UINT16);\r
209\r
210 // Allocate an array to handle maximum number of supported Boot Entry\r
211 SupportedBdsLoadOptions = (BDS_LOAD_OPTION**)AllocatePool(sizeof(BDS_LOAD_OPTION*) * BootOrderCount);\r
212\r
213 SupportedBdsLoadOptionCount = 0;\r
214\r
215 // Check if the signature is present in the list of the current Boot entries\r
216 for (Index = 0; Index < BootOrderCount; Index++) {\r
217 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);\r
218 if (!EFI_ERROR(Status)) {\r
219 if ((BdsLoadOption->OptionalDataSize >= sizeof(UINT32)) &&\r
220 (*(UINT32*)BdsLoadOption->OptionalData == LINUX_LOADER_SIGNATURE)) {\r
221 SupportedBdsLoadOptions[SupportedBdsLoadOptionCount++] = BdsLoadOption;\r
222 Choice = LINUX_LOADER_UPDATE;\r
223 }\r
224 }\r
225 }\r
226 }\r
227 FreePool (BootOrder);\r
228 }\r
229\r
230 if (Choice == LINUX_LOADER_NEW) {\r
231 Description[0] = '\0';\r
232 CmdLine[0] = '\0';\r
233 Initrd[0] = '\0';\r
234\r
235 BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));\r
236\r
237 DEBUG_CODE_BEGIN();\r
238 CHAR16* DevicePathTxt;\r
239 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
240\r
241 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
242 ASSERT_EFI_ERROR(Status);\r
243 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (LoadedImage->FilePath, TRUE, TRUE);\r
244\r
245 Print(L"EFI OS Loader: %s\n",DevicePathTxt);\r
246\r
247 FreePool(DevicePathTxt);\r
248 DEBUG_CODE_END();\r
249\r
250 //\r
251 // Fill the known fields of BdsLoadOption\r
252 //\r
253\r
254 BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;\r
255\r
256 // Get the full Device Path for this file\r
257 Status = gBS->HandleProtocol (LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathRoot);\r
258 ASSERT_EFI_ERROR(Status);\r
259\r
260 BdsLoadOption->FilePathList = AppendDevicePath (DevicePathRoot, LoadedImage->FilePath);\r
261 BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);\r
262 } else {\r
263 if (SupportedBdsLoadOptionCount > 1) {\r
264 for (Index = 0; Index < SupportedBdsLoadOptionCount; Index++) {\r
265 Print (L"[%d] %s\n",Index + 1,SupportedBdsLoadOptions[Index]->Description);\r
266 }\r
267\r
268 do {\r
269 Print (L"Update Boot Entry: ");\r
270 Status = GetHIInputInteger (&Choice);\r
271 if (Status == EFI_INVALID_PARAMETER) {\r
272 Print (L"\n");\r
273 return Status;\r
274 } else if ((Choice < 1) && (Choice > SupportedBdsLoadOptionCount)) {\r
275 Print (L"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount);\r
276 Status = EFI_INVALID_PARAMETER;\r
277 }\r
278 } while (EFI_ERROR(Status));\r
279 BdsLoadOption = SupportedBdsLoadOptions[Choice-1];\r
280 }\r
281 StrnCpy (Description, BdsLoadOption->Description, MAX_STR_INPUT);\r
282\r
283 LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)BdsLoadOption->OptionalData;\r
284 if (LinuxOptionalData->CmdLineLength > 0) {\r
285 CopyMem (CmdLine, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA), LinuxOptionalData->CmdLineLength);\r
286 } else {\r
287 CmdLine[0] = '\0';\r
288 }\r
289\r
290 if (LinuxOptionalData->InitrdPathListLength > 0) {\r
291 CopyMem (Initrd, (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA) + LinuxOptionalData->CmdLineLength, LinuxOptionalData->InitrdPathListLength);\r
292 } else {\r
293 Initrd[0] = L'\0';\r
294 }\r
295 DEBUG((EFI_D_ERROR,"L\n"));\r
296 }\r
297\r
298 // Description\r
299 Print (L"Description: ");\r
300 Status = EditHIInputStr (Description, MAX_STR_INPUT);\r
301 if (EFI_ERROR(Status)) {\r
302 return Status;\r
303 }\r
304 if (StrLen (Description) == 0) {\r
305 StrnCpy (Description, DEFAULT_BOOT_ENTRY_DESCRIPTION, MAX_STR_INPUT);\r
306 }\r
307 BdsLoadOption->Description = Description;\r
308\r
309 // CmdLine\r
310 Print (L"Command Line: ");\r
311 Status = EditHIInputAscii (CmdLine, MAX_ASCII_INPUT);\r
312 if (EFI_ERROR(Status)) {\r
313 return Status;\r
314 }\r
315\r
316 // Initrd\r
317 Print (L"Initrd name: ");\r
318 Status = EditHIInputStr (Initrd, MAX_STR_INPUT);\r
319 if (EFI_ERROR(Status)) {\r
320 return Status;\r
321 }\r
322\r
323 CmdLineLength = AsciiStrLen (CmdLine);\r
324 if (CmdLineLength > 0) {\r
325 CmdLineLength += sizeof(CHAR8);\r
326 }\r
327\r
328 InitrdPathListLength = StrLen (Initrd) * sizeof(CHAR16);\r
329 if (InitrdPathListLength > 0) {\r
330 InitrdPathListLength += sizeof(CHAR16);\r
331 }\r
332\r
333 BdsLoadOption->OptionalDataSize = sizeof(LINUX_LOADER_OPTIONAL_DATA) + CmdLineLength + InitrdPathListLength;\r
334\r
335 LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)AllocatePool (BdsLoadOption->OptionalDataSize);\r
336 BdsLoadOption->OptionalData = LinuxOptionalData;\r
337\r
338 LinuxOptionalData->Signature = LINUX_LOADER_SIGNATURE;\r
339 LinuxOptionalData->CmdLineLength = CmdLineLength;\r
340 LinuxOptionalData->InitrdPathListLength = InitrdPathListLength;\r
341\r
342 if (CmdLineLength > 0) {\r
343 CopyMem (LinuxOptionalData + 1, CmdLine, CmdLineLength);\r
344 }\r
345 if (InitrdPathListLength > 0) {\r
346 CopyMem ((UINT8*)(LinuxOptionalData + 1) + CmdLineLength, Initrd, InitrdPathListLength);\r
347 }\r
348\r
349 // Create or Update the boot entry\r
350 Status = BootOptionToLoadOptionVariable (BdsLoadOption);\r
351\r
352 return Status;\r
353}\r