3 * Copyright (c) 2011, 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"
18 #include <Protocol/DevicePathToText.h>
20 #define DEFAULT_BOOT_ENTRY_DESCRIPTION L"Linux"
21 #define MAX_STR_INPUT 300
22 #define MAX_ASCII_INPUT 300
27 } LINUX_LOADER_ACTION
;
32 IN OUT CHAR16
*CmdLine
,
44 for (CmdLineIndex
= StrLen (CmdLine
); CmdLineIndex
< MaxCmdLine
; ) {
45 Status
= gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &WaitIndex
);
46 ASSERT_EFI_ERROR (Status
);
48 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
49 ASSERT_EFI_ERROR (Status
);
51 // Unicode character is valid when Scancode is NUll
52 if (Key
.ScanCode
== SCAN_NULL
) {
53 // Scan code is NUll, hence read Unicode character
54 Char
= (CHAR8
)Key
.UnicodeChar
;
59 if ((Char
== CHAR_LINEFEED
) || (Char
== CHAR_CARRIAGE_RETURN
) || (Char
== 0x7f)) {
60 CmdLine
[CmdLineIndex
] = '\0';
64 } else if ((Key
.UnicodeChar
== L
'\b') || (Key
.ScanCode
== SCAN_LEFT
) || (Key
.ScanCode
== SCAN_DELETE
)){
65 if (CmdLineIndex
!= 0) {
69 } else if ((Key
.ScanCode
== SCAN_ESC
) || (Char
== 0x1B) || (Char
== 0x0)) {
70 return EFI_INVALID_PARAMETER
;
72 CmdLine
[CmdLineIndex
++] = Key
.UnicodeChar
;
73 Print (L
"%c", Key
.UnicodeChar
);
83 IN OUT CHAR8
*CmdLine
,
90 Str
= (CHAR16
*)AllocatePool (MaxCmdLine
* sizeof(CHAR16
));
91 AsciiStrToUnicodeStr (CmdLine
, Str
);
93 Status
= EditHIInputStr (Str
, MaxCmdLine
);
95 UnicodeStrToAsciiStr (Str
, CmdLine
);
111 Status
= EditHIInputStr (CmdLine
, 255);
112 if (!EFI_ERROR(Status
)) {
113 *Integer
= StrDecimalToUintn (CmdLine
);
121 GenerateDeviceDescriptionName (
122 IN EFI_HANDLE Handle
,
123 IN OUT CHAR16
* Description
127 EFI_COMPONENT_NAME_PROTOCOL
* ComponentName2Protocol
;
128 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
129 EFI_DEVICE_PATH_PROTOCOL
* DevicePathProtocol
;
131 CHAR16
* DevicePathTxt
;
132 EFI_DEVICE_PATH
* DevicePathNode
;
134 ComponentName2Protocol
= NULL
;
135 Status
= gBS
->HandleProtocol (Handle
, &gEfiComponentName2ProtocolGuid
, (VOID
**)&ComponentName2Protocol
);
136 if (!EFI_ERROR(Status
)) {
137 //TODO: Fixme. we must find the best langague
138 Status
= ComponentName2Protocol
->GetDriverName (ComponentName2Protocol
,"en",&DriverName
);
139 if (!EFI_ERROR(Status
)) {
140 StrnCpy (Description
,DriverName
,BOOT_DEVICE_DESCRIPTION_MAX
);
144 if (EFI_ERROR(Status
)) {
145 // Use the lastest non null entry of the Device path as a description
146 Status
= gBS
->HandleProtocol (Handle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathProtocol
);
147 if (EFI_ERROR(Status
)) {
151 // Convert the last non end-type Device Path Node in text for the description
152 DevicePathNode
= GetLastDevicePathNode (DevicePathProtocol
);
153 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
154 ASSERT_EFI_ERROR(Status
);
155 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(DevicePathNode
,TRUE
,TRUE
);
156 StrnCpy (Description
, DevicePathTxt
, BOOT_DEVICE_DESCRIPTION_MAX
);
157 FreePool (DevicePathTxt
);
166 IN EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
170 LINUX_LOADER_ACTION Choice
;
173 UINTN BootOrderCount
;
175 CHAR16 Description
[MAX_ASCII_INPUT
];
176 CHAR8 CmdLine
[MAX_ASCII_INPUT
];
177 CHAR16 Initrd
[MAX_STR_INPUT
];
178 UINT16 InitrdPathListLength
;
179 UINT16 CmdLineLength
;
180 BDS_LOAD_OPTION
* BdsLoadOption
;
181 BDS_LOAD_OPTION
** SupportedBdsLoadOptions
;
182 UINTN SupportedBdsLoadOptionCount
;
183 LINUX_LOADER_OPTIONAL_DATA
* LinuxOptionalData
;
184 EFI_DEVICE_PATH
* DevicePathRoot
;
186 SupportedBdsLoadOptions
= NULL
;
187 SupportedBdsLoadOptionCount
= 0;
190 Print (L
"[%d] Create new Linux Boot Entry\n",LINUX_LOADER_NEW
);
191 Print (L
"[%d] Update Linux Boot Entry\n",LINUX_LOADER_UPDATE
);
194 Status
= GetHIInputInteger (&Choice
);
195 if (Status
== EFI_INVALID_PARAMETER
) {
198 } else if ((Choice
!= LINUX_LOADER_NEW
) && (Choice
!= LINUX_LOADER_UPDATE
)) {
199 Print (L
"Error: the option should be either '%d' or '%d'\n",LINUX_LOADER_NEW
,LINUX_LOADER_UPDATE
);
200 Status
= EFI_INVALID_PARAMETER
;
202 } while (EFI_ERROR(Status
));
204 if (Choice
== LINUX_LOADER_UPDATE
) {
205 // If no compatible entry then we just create a new entry
206 Choice
= LINUX_LOADER_NEW
;
208 // Scan the OptionalData of every entry for the correct signature
209 Status
= GetEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
210 if (!EFI_ERROR(Status
)) {
211 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
213 // Allocate an array to handle maximum number of supported Boot Entry
214 SupportedBdsLoadOptions
= (BDS_LOAD_OPTION
**)AllocatePool(sizeof(BDS_LOAD_OPTION
*) * BootOrderCount
);
216 SupportedBdsLoadOptionCount
= 0;
218 // Check if the signature is present in the list of the current Boot entries
219 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
220 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
221 if (!EFI_ERROR(Status
)) {
222 if ((BdsLoadOption
->OptionalDataSize
>= sizeof(UINT32
)) &&
223 (*(UINT32
*)BdsLoadOption
->OptionalData
== LINUX_LOADER_SIGNATURE
)) {
224 SupportedBdsLoadOptions
[SupportedBdsLoadOptionCount
++] = BdsLoadOption
;
225 Choice
= LINUX_LOADER_UPDATE
;
232 if (Choice
== LINUX_LOADER_NEW
) {
233 Description
[0] = '\0';
237 BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
240 CHAR16
* DevicePathTxt
;
241 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
243 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
244 ASSERT_EFI_ERROR(Status
);
245 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (LoadedImage
->FilePath
, TRUE
, TRUE
);
247 Print(L
"EFI OS Loader: %s\n",DevicePathTxt
);
249 FreePool(DevicePathTxt
);
253 // Fill the known fields of BdsLoadOption
256 BdsLoadOption
->Attributes
= LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
;
258 // Get the full Device Path for this file
259 Status
= gBS
->HandleProtocol (LoadedImage
->DeviceHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathRoot
);
260 ASSERT_EFI_ERROR(Status
);
262 BdsLoadOption
->FilePathList
= AppendDevicePath (DevicePathRoot
, LoadedImage
->FilePath
);
263 BdsLoadOption
->FilePathListLength
= GetDevicePathSize (BdsLoadOption
->FilePathList
);
265 if (SupportedBdsLoadOptionCount
> 1) {
266 for (Index
= 0; Index
< SupportedBdsLoadOptionCount
; Index
++) {
267 Print (L
"[%d] %s\n",Index
+ 1,SupportedBdsLoadOptions
[Index
]->Description
);
271 Print (L
"Update Boot Entry: ");
272 Status
= GetHIInputInteger (&Choice
);
273 if (Status
== EFI_INVALID_PARAMETER
) {
276 } else if ((Choice
< 1) && (Choice
> SupportedBdsLoadOptionCount
)) {
277 Print (L
"Choose entry from 1 to %d\n",SupportedBdsLoadOptionCount
);
278 Status
= EFI_INVALID_PARAMETER
;
280 } while (EFI_ERROR(Status
));
281 BdsLoadOption
= SupportedBdsLoadOptions
[Choice
-1];
283 StrnCpy (Description
, BdsLoadOption
->Description
, MAX_STR_INPUT
);
285 LinuxOptionalData
= (LINUX_LOADER_OPTIONAL_DATA
*)BdsLoadOption
->OptionalData
;
286 if (LinuxOptionalData
->CmdLineLength
> 0) {
287 CopyMem (CmdLine
, (CHAR8
*)LinuxOptionalData
+ sizeof(LINUX_LOADER_OPTIONAL_DATA
), LinuxOptionalData
->CmdLineLength
);
292 if (LinuxOptionalData
->InitrdPathListLength
> 0) {
293 CopyMem (Initrd
, (CHAR8
*)LinuxOptionalData
+ sizeof(LINUX_LOADER_OPTIONAL_DATA
) + LinuxOptionalData
->CmdLineLength
, LinuxOptionalData
->InitrdPathListLength
);
297 DEBUG((EFI_D_ERROR
,"L\n"));
301 Print (L
"Description: ");
302 Status
= EditHIInputStr (Description
, MAX_STR_INPUT
);
303 if (EFI_ERROR(Status
)) {
306 if (StrLen (Description
) == 0) {
307 StrnCpy (Description
, DEFAULT_BOOT_ENTRY_DESCRIPTION
, MAX_STR_INPUT
);
309 BdsLoadOption
->Description
= Description
;
312 Print (L
"Command Line: ");
313 Status
= EditHIInputAscii (CmdLine
, MAX_ASCII_INPUT
);
314 if (EFI_ERROR(Status
)) {
319 Print (L
"Initrd name: ");
320 Status
= EditHIInputStr (Initrd
, MAX_STR_INPUT
);
321 if (EFI_ERROR(Status
)) {
325 CmdLineLength
= AsciiStrLen (CmdLine
);
326 if (CmdLineLength
> 0) {
327 CmdLineLength
+= sizeof(CHAR8
);
330 InitrdPathListLength
= StrLen (Initrd
) * sizeof(CHAR16
);
331 if (InitrdPathListLength
> 0) {
332 InitrdPathListLength
+= sizeof(CHAR16
);
335 BdsLoadOption
->OptionalDataSize
= sizeof(LINUX_LOADER_OPTIONAL_DATA
) + CmdLineLength
+ InitrdPathListLength
;
337 LinuxOptionalData
= (LINUX_LOADER_OPTIONAL_DATA
*)AllocatePool (BdsLoadOption
->OptionalDataSize
);
338 BdsLoadOption
->OptionalData
= LinuxOptionalData
;
340 LinuxOptionalData
->Signature
= LINUX_LOADER_SIGNATURE
;
341 LinuxOptionalData
->CmdLineLength
= CmdLineLength
;
342 LinuxOptionalData
->InitrdPathListLength
= InitrdPathListLength
;
344 if (CmdLineLength
> 0) {
345 CopyMem (LinuxOptionalData
+ 1, CmdLine
, CmdLineLength
);
347 if (InitrdPathListLength
> 0) {
348 CopyMem ((UINT8
*)(LinuxOptionalData
+ 1) + CmdLineLength
, Initrd
, InitrdPathListLength
);
351 // Create or Update the boot entry
352 Status
= BootOptionToLoadOptionVariable (BdsLoadOption
);