3 * Copyright (c) 2011-2012, ARM Limited. All rights reserved.
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
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.
15 #include "LinuxInternal.h"
17 #define DEFAULT_BOOT_ENTRY_DESCRIPTION L"Linux"
18 #define MAX_STR_INPUT 300
19 #define MAX_ASCII_INPUT 300
24 } LINUX_LOADER_ACTION
;
29 IN OUT CHAR16
*CmdLine
,
41 for (CmdLineIndex
= StrLen (CmdLine
); CmdLineIndex
< MaxCmdLine
; ) {
42 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
43 ASSERT_EFI_ERROR (Status
);
45 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
46 ASSERT_EFI_ERROR (Status
);
48 // Unicode character is valid when Scancode is NUll
49 if (Key
.ScanCode
== SCAN_NULL
) {
50 // Scan code is NUll, hence read Unicode character
51 Char
= (CHAR8
)Key
.UnicodeChar
;
56 if ((Char
== CHAR_LINEFEED
) || (Char
== CHAR_CARRIAGE_RETURN
) || (Char
== 0x7f)) {
57 CmdLine
[CmdLineIndex
] = '\0';
61 } else if ((Key
.UnicodeChar
== L
'\b') || (Key
.ScanCode
== SCAN_LEFT
) || (Key
.ScanCode
== SCAN_DELETE
)){
62 if (CmdLineIndex
!= 0) {
66 } else if ((Key
.ScanCode
== SCAN_ESC
) || (Char
== 0x1B) || (Char
== 0x0)) {
67 return EFI_INVALID_PARAMETER
;
69 CmdLine
[CmdLineIndex
++] = Key
.UnicodeChar
;
70 Print (L
"%c", Key
.UnicodeChar
);
80 IN OUT CHAR8
*CmdLine
,
87 Str
= (CHAR16
*)AllocatePool (MaxCmdLine
* sizeof(CHAR16
));
88 AsciiStrToUnicodeStr (CmdLine
, Str
);
90 Status
= EditHIInputStr (Str
, MaxCmdLine
);
92 UnicodeStrToAsciiStr (Str
, CmdLine
);
108 Status
= EditHIInputStr (CmdLine
, 255);
109 if (!EFI_ERROR(Status
)) {
110 *Integer
= StrDecimalToUintn (CmdLine
);
118 GenerateDeviceDescriptionName (
119 IN EFI_HANDLE Handle
,
120 IN OUT CHAR16
* Description
124 EFI_COMPONENT_NAME_PROTOCOL
* ComponentName2Protocol
;
125 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
126 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
128 CHAR16
* DevicePathTxt
;
129 EFI_DEVICE_PATH
* DevicePathNode
;
131 ComponentName2Protocol
= NULL
;
132 Status
= gBS
->HandleProtocol (Handle
, &gEfiComponentName2ProtocolGuid
, (VOID
**)&ComponentName2Protocol
);
133 if (!EFI_ERROR(Status
)) {
134 //TODO: Fixme. we must find the best langague
135 Status
= ComponentName2Protocol
->GetDriverName (ComponentName2Protocol
,"en",&DriverName
);
136 if (!EFI_ERROR(Status
)) {
137 StrnCpy (Description
,DriverName
,BOOT_DEVICE_DESCRIPTION_MAX
);
141 if (EFI_ERROR(Status
)) {
142 // Use the lastest non null entry of the Device path as a description
143 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
144 if (EFI_ERROR(Status
)) {
148 // Convert the last non end-type Device Path Node in text for the description
149 DevicePathNode
= GetLastDevicePathNode (DevicePathProtocol
);
150 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
151 ASSERT_EFI_ERROR(Status
);
152 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(DevicePathNode
,TRUE
,TRUE
);
153 StrnCpy (Description
, DevicePathTxt
, BOOT_DEVICE_DESCRIPTION_MAX
);
154 FreePool (DevicePathTxt
);
163 IN EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
167 LINUX_LOADER_ACTION Choice
;
170 UINTN BootOrderCount
;
172 CHAR16 Description
[MAX_ASCII_INPUT
];
173 CHAR8 CmdLine
[MAX_ASCII_INPUT
];
174 CHAR16 Initrd
[MAX_STR_INPUT
];
175 UINT16 InitrdPathListLength
;
176 UINT16 CmdLineLength
;
177 BDS_LOAD_OPTION
* BdsLoadOption
;
178 BDS_LOAD_OPTION
** SupportedBdsLoadOptions
;
179 UINTN SupportedBdsLoadOptionCount
;
180 LINUX_LOADER_OPTIONAL_DATA
* LinuxOptionalData
;
181 EFI_DEVICE_PATH
* DevicePathRoot
;
183 Choice
= (LINUX_LOADER_ACTION
)0;
184 SupportedBdsLoadOptions
= NULL
;
185 SupportedBdsLoadOptionCount
= 0;
188 Print (L
"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW
);
189 Print (L
"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE
);
192 Status
= GetHIInputInteger (&Choice
);
193 if (Status
== EFI_INVALID_PARAMETER
) {
196 } else if ((Choice
!= LINUX_LOADER_NEW
) && (Choice
!= LINUX_LOADER_UPDATE
)) {
197 Print (L
"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW
,LINUX_LOADER_UPDATE
);
198 Status
= EFI_INVALID_PARAMETER
;
200 } while (EFI_ERROR(Status
));
202 if (Choice
== LINUX_LOADER_UPDATE
) {
203 // If no compatible entry then we just create a new entry
204 Choice
= LINUX_LOADER_NEW
;
206 // Scan the OptionalData of every entry for the correct signature
207 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
208 if (!EFI_ERROR(Status
)) {
209 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
211 // Allocate an array to handle maximum number of supported Boot Entry
212 SupportedBdsLoadOptions
= (BDS_LOAD_OPTION
**)AllocatePool(sizeof(BDS_LOAD_OPTION
*) * BootOrderCount
);
214 SupportedBdsLoadOptionCount
= 0;
216 // Check if the signature is present in the list of the current Boot entries
217 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
218 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
219 if (!EFI_ERROR(Status
)) {
220 if ((BdsLoadOption
->OptionalDataSize
>= sizeof(UINT32
)) &&
221 (*(UINT32
*)BdsLoadOption
->OptionalData
== LINUX_LOADER_SIGNATURE
)) {
222 SupportedBdsLoadOptions
[SupportedBdsLoadOptionCount
++] = BdsLoadOption
;
223 Choice
= LINUX_LOADER_UPDATE
;
228 FreePool (BootOrder
);
231 if (Choice
== LINUX_LOADER_NEW
) {
232 Description
[0] = '\0';
236 BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
239 CHAR16
* DevicePathTxt
;
240 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
242 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
243 ASSERT_EFI_ERROR(Status
);
244 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (LoadedImage
->FilePath
, TRUE
, TRUE
);
246 Print(L
"EFI OS Loader: %s\n",DevicePathTxt
);
248 FreePool(DevicePathTxt
);
252 // Fill the known fields of BdsLoadOption
255 BdsLoadOption
->Attributes
= LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
;
257 // Get the full Device Path for this file
258 Status
= gBS
->HandleProtocol (LoadedImage
->DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathRoot
);
259 ASSERT_EFI_ERROR(Status
);
261 BdsLoadOption
->FilePathList
= AppendDevicePath (DevicePathRoot
, LoadedImage
->FilePath
);
262 BdsLoadOption
->FilePathListLength
= GetDevicePathSize (BdsLoadOption
->FilePathList
);
264 if (SupportedBdsLoadOptionCount
> 1) {
265 for (Index
= 0; Index
< SupportedBdsLoadOptionCount
; Index
++) {
266 Print (L
"[%d] %s\n",Index
+ 1,SupportedBdsLoadOptions
[Index
]->Description
);
270 Print (L
"Update Boot Entry: ");
271 Status
= GetHIInputInteger (&Choice
);
272 if (Status
== EFI_INVALID_PARAMETER
) {
275 } else if ((Choice
< 1) && (Choice
> SupportedBdsLoadOptionCount
)) {
276 Print (L
"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount
);
277 Status
= EFI_INVALID_PARAMETER
;
279 } while (EFI_ERROR(Status
));
280 BdsLoadOption
= SupportedBdsLoadOptions
[Choice
-1];
282 StrnCpy (Description
, BdsLoadOption
->Description
, MAX_STR_INPUT
);
284 LinuxOptionalData
= (LINUX_LOADER_OPTIONAL_DATA
*)BdsLoadOption
->OptionalData
;
285 if (LinuxOptionalData
->CmdLineLength
> 0) {
286 CopyMem (CmdLine
, (CHAR8
*)LinuxOptionalData
+ sizeof(LINUX_LOADER_OPTIONAL_DATA
), LinuxOptionalData
->CmdLineLength
);
291 if (LinuxOptionalData
->InitrdPathListLength
> 0) {
292 CopyMem (Initrd
, (CHAR8
*)LinuxOptionalData
+ sizeof(LINUX_LOADER_OPTIONAL_DATA
) + LinuxOptionalData
->CmdLineLength
, LinuxOptionalData
->InitrdPathListLength
);
296 DEBUG((EFI_D_ERROR
,"L\n"));
300 Print (L
"Description: ");
301 Status
= EditHIInputStr (Description
, MAX_STR_INPUT
);
302 if (EFI_ERROR(Status
)) {
305 if (StrLen (Description
) == 0) {
306 StrnCpy (Description
, DEFAULT_BOOT_ENTRY_DESCRIPTION
, MAX_STR_INPUT
);
308 BdsLoadOption
->Description
= Description
;
311 Print (L
"Command Line: ");
312 Status
= EditHIInputAscii (CmdLine
, MAX_ASCII_INPUT
);
313 if (EFI_ERROR(Status
)) {
318 Print (L
"Initrd name: ");
319 Status
= EditHIInputStr (Initrd
, MAX_STR_INPUT
);
320 if (EFI_ERROR(Status
)) {
324 CmdLineLength
= AsciiStrLen (CmdLine
);
325 if (CmdLineLength
> 0) {
326 CmdLineLength
+= sizeof(CHAR8
);
329 InitrdPathListLength
= StrLen (Initrd
) * sizeof(CHAR16
);
330 if (InitrdPathListLength
> 0) {
331 InitrdPathListLength
+= sizeof(CHAR16
);
334 BdsLoadOption
->OptionalDataSize
= sizeof(LINUX_LOADER_OPTIONAL_DATA
) + CmdLineLength
+ InitrdPathListLength
;
336 LinuxOptionalData
= (LINUX_LOADER_OPTIONAL_DATA
*)AllocatePool (BdsLoadOption
->OptionalDataSize
);
337 BdsLoadOption
->OptionalData
= LinuxOptionalData
;
339 LinuxOptionalData
->Signature
= LINUX_LOADER_SIGNATURE
;
340 LinuxOptionalData
->CmdLineLength
= CmdLineLength
;
341 LinuxOptionalData
->InitrdPathListLength
= InitrdPathListLength
;
343 if (CmdLineLength
> 0) {
344 CopyMem (LinuxOptionalData
+ 1, CmdLine
, CmdLineLength
);
346 if (InitrdPathListLength
> 0) {
347 CopyMem ((UINT8
*)(LinuxOptionalData
+ 1) + CmdLineLength
, Initrd
, InitrdPathListLength
);
350 // Create or Update the boot entry
351 Status
= BootOptionToLoadOptionVariable (BdsLoadOption
);