1 /** @file
2 Main file for BCFG command.
3
4 (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include <Uefi.h>
18
19 #include <Guid/GlobalVariable.h>
20 #include <Guid/ShellLibHiiGuid.h>
21
22 #include <Protocol/Shell.h>
23 #include <Protocol/ShellParameters.h>
24 #include <Protocol/DevicePath.h>
25 #include <Protocol/LoadedImage.h>
26 #include <Protocol/UnicodeCollation.h>
27
28 #include <Library/BaseLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/PcdLib.h>
33 #include <Library/ShellCommandLib.h>
34 #include <Library/ShellLib.h>
35 #include <Library/SortLib.h>
36 #include <Library/UefiLib.h>
37 #include <Library/UefiRuntimeServicesTableLib.h>
38 #include <Library/UefiBootServicesTableLib.h>
39 #include <Library/HiiLib.h>
40 #include <Library/FileHandleLib.h>
41 #include <Library/PrintLib.h>
42 #include <Library/HandleParsingLib.h>
43 #include <Library/DevicePathLib.h>
44
45 STATIC CONST CHAR16 mFileName[] = L"ShellCommands";
46 STATIC EFI_HANDLE gShellBcfgHiiHandle = NULL;
47
48 typedef enum {
49 BcfgTargetBootOrder = 0,
50 BcfgTargetDriverOrder = 1,
51 BcfgTargetMax = 2
52 } BCFG_OPERATION_TARGET;
53
54 typedef enum {
55 BcfgTypeDump = 0,
56 BcfgTypeAdd = 1,
57 BcfgTypeAddp = 2,
58 BcfgTypeAddh = 3,
59 BcfgTypeRm = 4,
60 BcfgTypeMv = 5,
61 BcfgTypeOpt = 6,
62 BcfgTypeMax = 7
63 } BCFG_OPERATION_TYPE;
64
65 typedef struct {
66 BCFG_OPERATION_TARGET Target;
67 BCFG_OPERATION_TYPE Type;
68 UINT16 Number1;
69 UINT16 Number2;
70 UINTN HandleIndex;
71 CHAR16 *FileName;
72 CHAR16 *Description;
73 UINT16 *Order;
74 CONST CHAR16 *OptData;
75 } BGFG_OPERATION;
76
77 /**
78 Update the optional data for a boot or driver option.
79
80 If optional data exists it will be changed.
81
82 @param[in] Index The boot or driver option index update.
83 @param[in] DataSize The size in bytes of Data.
84 @param[in] Data The buffer for the optioanl data.
85 @param[in] Target The target of the operation.
86
87 @retval EFI_SUCCESS The data was sucessfully updated.
88 @retval other A error occured.
89 **/
90 EFI_STATUS
UpdateOptionalData(UINT16 Index,UINTN DataSize,UINT8 * Data,IN CONST BCFG_OPERATION_TARGET Target)91 UpdateOptionalData(
92 UINT16 Index,
93 UINTN DataSize,
94 UINT8 *Data,
95 IN CONST BCFG_OPERATION_TARGET Target
96 )
97 {
98 EFI_STATUS Status;
99 CHAR16 VariableName[12];
100 UINTN OriginalSize;
101 UINT8 *OriginalData;
102 UINTN NewSize;
103 UINT8 *NewData;
104 UINTN OriginalOptionDataSize;
105
106 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", Index);
107
108 OriginalSize = 0;
109 OriginalData = NULL;
110 NewData = NULL;
111 NewSize = 0;
112
113 Status = gRT->GetVariable(
114 VariableName,
115 (EFI_GUID*)&gEfiGlobalVariableGuid,
116 NULL,
117 &OriginalSize,
118 OriginalData);
119 if (Status == EFI_BUFFER_TOO_SMALL) {
120 OriginalData = AllocateZeroPool(OriginalSize);
121 if (OriginalData == NULL) {
122 return (EFI_OUT_OF_RESOURCES);
123 }
124 Status = gRT->GetVariable(
125 VariableName,
126 (EFI_GUID*)&gEfiGlobalVariableGuid,
127 NULL,
128 &OriginalSize,
129 OriginalData);
130 }
131
132 if (!EFI_ERROR(Status)) {
133 //
134 // Allocate new struct and discard old optional data.
135 //
136 ASSERT (OriginalData != NULL);
137 OriginalOptionDataSize = sizeof(UINT32) + sizeof(UINT16) + StrSize(((CHAR16*)(OriginalData + sizeof(UINT32) + sizeof(UINT16))));
138 OriginalOptionDataSize += (*(UINT16*)(OriginalData + sizeof(UINT32)));
139 OriginalOptionDataSize -= OriginalSize;
140 NewSize = OriginalSize - OriginalOptionDataSize + DataSize;
141 NewData = AllocateCopyPool(NewSize, OriginalData);
142 if (NewData == NULL) {
143 Status = EFI_OUT_OF_RESOURCES;
144 } else {
145 CopyMem(NewData + OriginalSize - OriginalOptionDataSize, Data, DataSize);
146 }
147 }
148
149 if (!EFI_ERROR(Status)) {
150 //
151 // put the data back under the variable
152 //
153 Status = gRT->SetVariable(
154 VariableName,
155 (EFI_GUID*)&gEfiGlobalVariableGuid,
156 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
157 NewSize,
158 NewData);
159 }
160
161 SHELL_FREE_NON_NULL(OriginalData);
162 SHELL_FREE_NON_NULL(NewData);
163 return (Status);
164 }
165
166 /**
167 This function will get a CRC for a boot option.
168
169 @param[in, out] Crc The CRC value to return.
170 @param[in] BootIndex The boot option index to CRC.
171
172 @retval EFI_SUCCESS The CRC was sucessfully returned.
173 @retval other A error occured.
174 **/
175 EFI_STATUS
GetBootOptionCrc(UINT32 * Crc,UINT16 BootIndex)176 GetBootOptionCrc(
177 UINT32 *Crc,
178 UINT16 BootIndex
179 )
180 {
181 CHAR16 VariableName[12];
182 EFI_STATUS Status;
183 UINT8 *Buffer;
184 UINTN BufferSize;
185
186 Buffer = NULL;
187 BufferSize = 0;
188
189 //
190 // Get the data Buffer
191 //
192 UnicodeSPrint(VariableName, sizeof(VariableName), L"%Boot%04x", BootIndex);
193 Status = gRT->GetVariable(
194 VariableName,
195 (EFI_GUID*)&gEfiGlobalVariableGuid,
196 NULL,
197 &BufferSize,
198 NULL);
199 if (Status == EFI_BUFFER_TOO_SMALL) {
200 Buffer = AllocateZeroPool(BufferSize);
201 Status = gRT->GetVariable(
202 VariableName,
203 (EFI_GUID*)&gEfiGlobalVariableGuid,
204 NULL,
205 &BufferSize,
206 Buffer);
207 }
208
209 //
210 // Get the CRC computed
211 //
212 if (!EFI_ERROR(Status)) {
213 Status = gBS->CalculateCrc32 (Buffer, BufferSize, Crc);
214 }
215
216 SHELL_FREE_NON_NULL(Buffer);
217 return EFI_SUCCESS;
218 }
219
220 /**
221 This function will populate the device path protocol parameter based on TheHandle.
222
223 @param[in] TheHandle Driver handle.
224 @param[in, out] FilePath On a sucessful return the device path to the handle.
225
226 @retval EFI_SUCCESS The device path was sucessfully returned.
227 @retval other A error from gBS->HandleProtocol.
228
229 @sa HandleProtocol
230 **/
231 EFI_STATUS
GetDevicePathForDriverHandle(IN EFI_HANDLE TheHandle,IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath)232 GetDevicePathForDriverHandle (
233 IN EFI_HANDLE TheHandle,
234 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath
235 )
236 {
237 EFI_STATUS Status;
238 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
239 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
240
241 Status = gBS->OpenProtocol (
242 TheHandle,
243 &gEfiLoadedImageProtocolGuid,
244 (VOID**)&LoadedImage,
245 gImageHandle,
246 NULL,
247 EFI_OPEN_PROTOCOL_GET_PROTOCOL
248 );
249 if (!EFI_ERROR (Status)) {
250 Status = gBS->OpenProtocol (
251 LoadedImage->DeviceHandle,
252 &gEfiDevicePathProtocolGuid,
253 (VOID**)&ImageDevicePath,
254 gImageHandle,
255 NULL,
256 EFI_OPEN_PROTOCOL_GET_PROTOCOL
257 );
258 if (!EFI_ERROR (Status)) {
259 // *DevPath = DuplicateDevicePath (ImageDevicePath);
260 // *FilePath = DuplicateDevicePath (LoadedImage->FilePath);
261 *FilePath = AppendDevicePath(ImageDevicePath,LoadedImage->FilePath);
262 gBS->CloseProtocol(
263 LoadedImage->DeviceHandle,
264 &gEfiDevicePathProtocolGuid,
265 gImageHandle,
266 NULL);
267 }
268 gBS->CloseProtocol(
269 TheHandle,
270 &gEfiLoadedImageProtocolGuid,
271 gImageHandle,
272 NULL);
273 }
274 return (Status);
275 }
276
277 /**
278 Function to add a option.
279
280 @param[in] Position The position to add Target at.
281 @param[in] File The file to make the target.
282 @param[in] Desc The description text.
283 @param[in] CurrentOrder The pointer to the current order of items.
284 @param[in] OrderCount The number if items in CurrentOrder.
285 @param[in] Target The info on the option to add.
286 @param[in] UseHandle TRUE to use HandleNumber, FALSE to use File and Desc.
287 @param[in] UsePath TRUE to convert to devicepath.
288 @param[in] HandleNumber The handle number to add.
289
290 @retval SHELL_SUCCESS The operation was successful.
291 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
292 **/
293 SHELL_STATUS
BcfgAdd(IN UINTN Position,IN CONST CHAR16 * File,IN CONST CHAR16 * Desc,IN CONST UINT16 * CurrentOrder,IN CONST UINTN OrderCount,IN CONST BCFG_OPERATION_TARGET Target,IN CONST BOOLEAN UseHandle,IN CONST BOOLEAN UsePath,IN CONST UINTN HandleNumber)294 BcfgAdd(
295 IN UINTN Position,
296 IN CONST CHAR16 *File,
297 IN CONST CHAR16 *Desc,
298 IN CONST UINT16 *CurrentOrder,
299 IN CONST UINTN OrderCount,
300 IN CONST BCFG_OPERATION_TARGET Target,
301 IN CONST BOOLEAN UseHandle,
302 IN CONST BOOLEAN UsePath,
303 IN CONST UINTN HandleNumber
304 )
305 {
306 EFI_STATUS Status;
307 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
308 EFI_DEVICE_PATH_PROTOCOL *DevPath;
309 EFI_DEVICE_PATH_PROTOCOL *FilePath;
310 CHAR16 *Str;
311 UINT8 *TempByteBuffer;
312 UINT8 *TempByteStart;
313 EFI_SHELL_FILE_INFO *Arg;
314 EFI_SHELL_FILE_INFO *FileList;
315 CHAR16 OptionStr[40];
316 UINTN DescSize, FilePathSize;
317 BOOLEAN Found;
318 UINTN TargetLocation;
319 UINTN Index;
320 EFI_HANDLE *Handles;
321 EFI_HANDLE CurHandle;
322 UINTN DriverBindingHandleCount;
323 UINTN ParentControllerHandleCount;
324 UINTN ChildControllerHandleCount;
325 SHELL_STATUS ShellStatus;
326 UINT16 *NewOrder;
327
328 if (!UseHandle) {
329 if (File == NULL || Desc == NULL) {
330 return (SHELL_INVALID_PARAMETER);
331 }
332 } else {
333 if (HandleNumber == 0) {
334 return (SHELL_INVALID_PARAMETER);
335 }
336 }
337
338 if (Position > OrderCount) {
339 Position = OrderCount;
340 }
341
342 Str = NULL;
343 FilePath = NULL;
344 FileList = NULL;
345 Handles = NULL;
346 ShellStatus = SHELL_SUCCESS;
347 TargetLocation = 0xFFFF;
348
349 if (UseHandle) {
350 CurHandle = ConvertHandleIndexToHandle(HandleNumber);
351 if (CurHandle == NULL) {
352 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
353 ShellStatus = SHELL_INVALID_PARAMETER;
354 } else {
355 if (Target == BcfgTargetBootOrder) {
356 //
357 //Make sure that the handle should point to a real controller
358 //
359 Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
360 CurHandle,
361 &DriverBindingHandleCount,
362 NULL);
363
364 Status = PARSE_HANDLE_DATABASE_PARENTS (
365 CurHandle,
366 &ParentControllerHandleCount,
367 NULL);
368
369 Status = ParseHandleDatabaseForChildControllers (
370 CurHandle,
371 &ChildControllerHandleCount,
372 NULL);
373
374 if (DriverBindingHandleCount > 0
375 || ParentControllerHandleCount > 0
376 || ChildControllerHandleCount > 0) {
377 FilePath = NULL;
378 Status = gBS->HandleProtocol (
379 CurHandle,
380 &gEfiDevicePathProtocolGuid,
381 (VOID**)&FilePath);
382 }
383 if (EFI_ERROR (Status)) {
384 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_HANDLE), gShellBcfgHiiHandle, L"bcfg", HandleNumber);
385 ShellStatus = SHELL_INVALID_PARAMETER;
386 }
387 } else {
388 //
389 //Make sure that the handle should point to driver, not a controller.
390 //
391 Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (
392 CurHandle,
393 &DriverBindingHandleCount,
394 NULL);
395
396 Status = PARSE_HANDLE_DATABASE_PARENTS (
397 CurHandle,
398 &ParentControllerHandleCount,
399 NULL);
400
401 Status = ParseHandleDatabaseForChildControllers (
402 CurHandle,
403 &ChildControllerHandleCount,
404 NULL);
405
406 Status = gBS->HandleProtocol (
407 CurHandle,
408 &gEfiDevicePathProtocolGuid,
409 (VOID**)&FilePath);
410
411 if (DriverBindingHandleCount > 0
412 || ParentControllerHandleCount > 0
413 || ChildControllerHandleCount > 0
414 || !EFI_ERROR(Status) ) {
415 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Handle Number");
416 ShellStatus = SHELL_INVALID_PARAMETER;
417 } else {
418 //
419 // Get the DevicePath from the loaded image information.
420 //
421 Status = GetDevicePathForDriverHandle(CurHandle, &FilePath);
422 }
423 }
424 }
425 } else {
426 //
427 // Get file info
428 //
429 ShellOpenFileMetaArg ((CHAR16*)File, EFI_FILE_MODE_READ, &FileList);
430
431 if (FileList == NULL) {
432 //
433 // If filename matched nothing fail
434 //
435 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellBcfgHiiHandle, L"bcfg", File);
436 ShellStatus = SHELL_INVALID_PARAMETER;
437 } else if (FileList->Link.ForwardLink != FileList->Link.BackLink) {
438 //
439 // If filename expanded to multiple names, fail
440 //
441 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE), gShellBcfgHiiHandle, L"bcfg", File);
442 ShellStatus = SHELL_INVALID_PARAMETER;
443 } else {
444 Arg = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link);
445 if (EFI_ERROR(Arg->Status)) {
446 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_OPEN), gShellBcfgHiiHandle, L"bcfg", File);
447 ShellStatus = SHELL_INVALID_PARAMETER;
448 } else {
449 //
450 // Build FilePath to the filename
451 //
452
453 //
454 // get the device path
455 //
456 DevicePath = gEfiShellProtocol->GetDevicePathFromFilePath(Arg->FullName);
457 if (DevicePath == NULL) {
458 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_FILE_DP), gShellBcfgHiiHandle, L"bcfg", Arg->FullName);
459 ShellStatus = SHELL_UNSUPPORTED;
460 } else {
461 if (UsePath) {
462 DevPath = DevicePath;
463 ShellStatus = SHELL_INVALID_PARAMETER;
464 while (!IsDevicePathEnd(DevPath)) {
465 if ((DevicePathType(DevPath) == MEDIA_DEVICE_PATH) &&
466 (DevicePathSubType(DevPath) == MEDIA_HARDDRIVE_DP)) {
467
468 //
469 // If we find it use it instead
470 //
471 ShellStatus = SHELL_SUCCESS;
472 FilePath = DuplicateDevicePath (DevPath);
473 break;
474 }
475 DevPath = NextDevicePathNode(DevPath);
476 }
477 } else {
478 FilePath = DuplicateDevicePath(DevicePath);
479 }
480 FreePool(DevicePath);
481 }
482 }
483 }
484 }
485
486
487 if (ShellStatus == SHELL_SUCCESS) {
488 //
489 // Find a free target ,a brute force implementation
490 //
491 Found = FALSE;
492 for (TargetLocation=0; TargetLocation < 0xFFFF; TargetLocation++) {
493 Found = TRUE;
494 for (Index=0; Index < OrderCount; Index++) {
495 if (CurrentOrder[Index] == TargetLocation) {
496 Found = FALSE;
497 break;
498 }
499 }
500
501 if (Found) {
502 break;
503 }
504 }
505
506 if (TargetLocation == 0xFFFF) {
507 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET_NF), gShellBcfgHiiHandle, L"bcfg");
508 } else {
509 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_TARGET), gShellBcfgHiiHandle, TargetLocation);
510 }
511 }
512
513 if (ShellStatus == SHELL_SUCCESS) {
514 //
515 // Add the option
516 //
517 DescSize = StrSize(Desc);
518 FilePathSize = GetDevicePathSize (FilePath);
519
520 TempByteBuffer = AllocateZeroPool(sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize);
521 if (TempByteBuffer != NULL) {
522 TempByteStart = TempByteBuffer;
523 *((UINT32 *) TempByteBuffer) = LOAD_OPTION_ACTIVE; // Attributes
524 TempByteBuffer += sizeof (UINT32);
525
526 *((UINT16 *) TempByteBuffer) = (UINT16)FilePathSize; // FilePathListLength
527 TempByteBuffer += sizeof (UINT16);
528
529 CopyMem (TempByteBuffer, Desc, DescSize);
530 TempByteBuffer += DescSize;
531 ASSERT (FilePath != NULL);
532 CopyMem (TempByteBuffer, FilePath, FilePathSize);
533
534 UnicodeSPrint (OptionStr, sizeof(OptionStr), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", TargetLocation);
535 Status = gRT->SetVariable (
536 OptionStr,
537 &gEfiGlobalVariableGuid,
538 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
539 sizeof(UINT32) + sizeof(UINT16) + DescSize + FilePathSize,
540 TempByteStart
541 );
542
543 FreePool(TempByteStart);
544 } else {
545 Status = EFI_OUT_OF_RESOURCES;
546 }
547
548 if (EFI_ERROR(Status)) {
549 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", OptionStr);
550 } else {
551 NewOrder = AllocateZeroPool ((OrderCount + 1) * sizeof (NewOrder[0]));
552 if (NewOrder != NULL) {
553 CopyMem (NewOrder, CurrentOrder, (OrderCount) * sizeof (NewOrder[0]));
554
555 //
556 // Insert target into order list
557 //
558 for (Index = OrderCount; Index > Position; Index--) {
559 NewOrder[Index] = NewOrder[Index - 1];
560 }
561
562 NewOrder[Position] = (UINT16) TargetLocation;
563 Status = gRT->SetVariable (
564 Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder",
565 &gEfiGlobalVariableGuid,
566 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
567 (OrderCount + 1) * sizeof (UINT16),
568 NewOrder
569 );
570
571 FreePool (NewOrder);
572
573 if (EFI_ERROR (Status)) {
574 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder ? L"BootOrder" : L"DriverOrder");
575 ShellStatus = SHELL_INVALID_PARAMETER;
576 } else {
577 Print (L"bcfg: Add %s as %x\n", OptionStr, Position);
578 }
579 }
580 }
581 }
582
583 //
584 //If always Free FilePath, will free devicepath in system when use "addh"
585 //
586 if (FilePath!=NULL && !UseHandle) {
587 FreePool (FilePath);
588 }
589
590 if (Str != NULL) {
591 FreePool(Str);
592 }
593
594 if (Handles != NULL) {
595 FreePool (Handles);
596 }
597
598 if (FileList != NULL) {
599 ShellCloseFileMetaArg (&FileList);
600 }
601
602 return (ShellStatus);
603 }
604
605 /**
606 Funciton to remove an item.
607
608 @param[in] Target The target item to move.
609 @param[in] CurrentOrder The pointer to the current order of items.
610 @param[in] OrderCount The number if items in CurrentOrder.
611 @param[in] Location The current location of the Target.
612
613 @retval SHELL_SUCCESS The operation was successful.
614 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
615 **/
616 SHELL_STATUS
BcfgRemove(IN CONST BCFG_OPERATION_TARGET Target,IN CONST UINT16 * CurrentOrder,IN CONST UINTN OrderCount,IN CONST UINT16 Location)617 BcfgRemove(
618 IN CONST BCFG_OPERATION_TARGET Target,
619 IN CONST UINT16 *CurrentOrder,
620 IN CONST UINTN OrderCount,
621 IN CONST UINT16 Location
622 )
623 {
624 CHAR16 VariableName[12];
625 UINT16 *NewOrder;
626 EFI_STATUS Status;
627 UINTN NewCount;
628
629 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Target == BcfgTargetBootOrder?L"Boot":L"Driver", CurrentOrder[Location]);
630 Status = gRT->SetVariable(
631 VariableName,
632 (EFI_GUID*)&gEfiGlobalVariableGuid,
633 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
634 0,
635 NULL);
636 if (EFI_ERROR(Status)) {
637 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
638 return (SHELL_INVALID_PARAMETER);
639 }
640 NewOrder = AllocateZeroPool(OrderCount*sizeof(CurrentOrder[0]));
641 if (NewOrder != NULL) {
642 NewCount = OrderCount;
643 CopyMem(NewOrder, CurrentOrder, OrderCount*sizeof(CurrentOrder[0]));
644 CopyMem(NewOrder+Location, NewOrder+Location+1, (OrderCount - Location - 1)*sizeof(CurrentOrder[0]));
645 NewCount--;
646
647 Status = gRT->SetVariable(
648 Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
649 (EFI_GUID*)&gEfiGlobalVariableGuid,
650 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
651 NewCount*sizeof(NewOrder[0]),
652 NewOrder);
653 FreePool(NewOrder);
654 } else {
655 Status = EFI_OUT_OF_RESOURCES;
656 }
657 if (EFI_ERROR(Status)) {
658 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
659 return (SHELL_INVALID_PARAMETER);
660 }
661 return (SHELL_SUCCESS);
662 }
663
664 /**
665 Funciton to move a item to another location.
666
667 @param[in] Target The target item to move.
668 @param[in] CurrentOrder The pointer to the current order of items.
669 @param[in] OrderCount The number if items in CurrentOrder.
670 @param[in] OldLocation The current location of the Target.
671 @param[in] NewLocation The desired location of the Target.
672
673 @retval SHELL_SUCCESS The operation was successful.
674 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
675 **/
676 SHELL_STATUS
BcfgMove(IN CONST BCFG_OPERATION_TARGET Target,IN CONST UINT16 * CurrentOrder,IN CONST UINTN OrderCount,IN CONST UINT16 OldLocation,IN UINT16 NewLocation)677 BcfgMove(
678 IN CONST BCFG_OPERATION_TARGET Target,
679 IN CONST UINT16 *CurrentOrder,
680 IN CONST UINTN OrderCount,
681 IN CONST UINT16 OldLocation,
682 IN UINT16 NewLocation
683 )
684 {
685 UINT16 *NewOrder;
686 EFI_STATUS Status;
687 UINT16 Temp;
688
689 NewOrder = AllocateCopyPool(OrderCount*sizeof(CurrentOrder[0]), CurrentOrder);
690 if (NewOrder == NULL) {
691 return (SHELL_OUT_OF_RESOURCES);
692 }
693
694 //
695 // correct the new location
696 //
697 if (NewLocation >= OrderCount) {
698 if (OrderCount > 0) {
699 NewLocation = (UINT16)OrderCount - 1;
700 } else {
701 NewLocation = 0;
702 }
703 }
704
705 Temp = CurrentOrder[OldLocation];
706 CopyMem(NewOrder+OldLocation, NewOrder+OldLocation+1, (OrderCount - OldLocation - 1)*sizeof(CurrentOrder[0]));
707 CopyMem(NewOrder+NewLocation+1, NewOrder+NewLocation, (OrderCount - NewLocation - 1)*sizeof(CurrentOrder[0]));
708 NewOrder[NewLocation] = Temp;
709
710 Status = gRT->SetVariable(
711 Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
712 (EFI_GUID*)&gEfiGlobalVariableGuid,
713 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
714 OrderCount*sizeof(CurrentOrder[0]),
715 NewOrder);
716
717 FreePool(NewOrder);
718
719 if (EFI_ERROR(Status)) {
720 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_WRITE_FAIL), gShellBcfgHiiHandle, L"bcfg", Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder");
721 return (SHELL_INVALID_PARAMETER);
722 }
723 return (SHELL_SUCCESS);
724 }
725
726 /**
727 Function to add optional data to an option.
728
729 @param[in] OptData The optional data to add.
730 @param[in] CurrentOrder The pointer to the current order of items.
731 @param[in] OrderCount The number if items in CurrentOrder.
732 @param[in] Target The target of the operation.
733
734 @retval SHELL_SUCCESS The operation was succesful.
735 **/
736 SHELL_STATUS
BcfgAddOpt(IN CONST CHAR16 * OptData,IN CONST UINT16 * CurrentOrder,IN CONST UINTN OrderCount,IN CONST BCFG_OPERATION_TARGET Target)737 BcfgAddOpt(
738 IN CONST CHAR16 *OptData,
739 IN CONST UINT16 *CurrentOrder,
740 IN CONST UINTN OrderCount,
741 IN CONST BCFG_OPERATION_TARGET Target
742 )
743 {
744 EFI_KEY_OPTION NewKeyOption;
745 EFI_KEY_OPTION *KeyOptionBuffer;
746 SHELL_STATUS ShellStatus;
747 EFI_STATUS Status;
748 UINT16 OptionIndex;
749 UINT16 LoopCounter;
750 UINT64 Intermediate;
751 CONST CHAR16 *Temp;
752 CONST CHAR16 *Walker;
753 CHAR16 *FileName;
754 CHAR16 *Temp2;
755 CHAR16 *Data;
756 UINT32 KeyIndex;
757 CHAR16 VariableName[12];
758 VOID *VariableData;
759
760 SHELL_FILE_HANDLE FileHandle;
761
762 Status = EFI_SUCCESS;
763 ShellStatus = SHELL_SUCCESS;
764 Walker = OptData;
765 FileName = NULL;
766 Data = NULL;
767 KeyOptionBuffer = NULL;
768 VariableData = NULL;
769
770 ZeroMem(&NewKeyOption, sizeof(EFI_KEY_OPTION));
771 ZeroMem(VariableName, sizeof(VariableName));
772
773 while(Walker[0] == L' ') {
774 Walker++;
775 }
776
777 //
778 // Get the index of the variable we are changing.
779 //
780 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
781 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL || ((UINT16)Intermediate) > ((UINT16)OrderCount)) {
782 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
783 ShellStatus = SHELL_INVALID_PARAMETER;
784 return (ShellStatus);
785 }
786 OptionIndex = (UINT16)Intermediate;
787
788 Temp = StrStr(Walker, L" ");
789 if (Temp != NULL) {
790 Walker = Temp;
791 }
792 while(Walker[0] == L' ') {
793 Walker++;
794 }
795
796 //
797 // determine whether we have file with data, quote delimited information, or a hot-key
798 //
799 if (Walker[0] == L'\"') {
800 //
801 // quoted filename or quoted information.
802 //
803 Temp = StrStr(Walker+1, L"\"");
804 if (Temp == NULL || StrLen(Temp) != 1) {
805 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
806 ShellStatus = SHELL_INVALID_PARAMETER;
807 } else {
808 FileName = StrnCatGrow(&FileName, NULL, Walker+1, 0);
809 if (FileName == NULL) {
810 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellBcfgHiiHandle, L"bcfg");
811 ShellStatus = SHELL_OUT_OF_RESOURCES;
812 return (ShellStatus);
813 }
814 Temp2 = StrStr(FileName, L"\"");
815 ASSERT(Temp2 != NULL);
816 Temp2[0] = CHAR_NULL;
817 Temp2++;
818 if (StrLen(Temp2)>0) {
819 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
820 ShellStatus = SHELL_INVALID_PARAMETER;
821 }
822 if (EFI_ERROR(ShellFileExists(Walker))) {
823 //
824 // Not a file. must be misc information.
825 //
826 Data = FileName;
827 FileName = NULL;
828 } else {
829 FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
830 }
831 }
832 } else {
833 //
834 // filename or hot key information.
835 //
836 if (StrStr(Walker, L" ") == NULL) {
837 //
838 // filename
839 //
840 if (EFI_ERROR(ShellFileExists(Walker))) {
841 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FIND_FAIL), gShellBcfgHiiHandle, L"bcfg", Walker);
842 ShellStatus = SHELL_INVALID_PARAMETER;
843 } else {
844 FileName = StrnCatGrow(&FileName, NULL, Walker, 0);
845 }
846 } else {
847 if (Target != BcfgTargetBootOrder) {
848 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_BOOT_ONLY), gShellBcfgHiiHandle, L"bcfg");
849 ShellStatus = SHELL_INVALID_PARAMETER;
850 }
851
852 if (ShellStatus == SHELL_SUCCESS) {
853 //
854 // Get hot key information
855 //
856 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
857 if (EFI_ERROR(Status) || (((UINT32)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
858 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
859 ShellStatus = SHELL_INVALID_PARAMETER;
860 }
861 NewKeyOption.KeyData.PackedValue = (UINT32)Intermediate;
862 Temp = StrStr(Walker, L" ");
863 if (Temp != NULL) {
864 Walker = Temp;
865 }
866 while(Walker[0] == L' ') {
867 Walker++;
868 }
869 }
870
871 if (ShellStatus == SHELL_SUCCESS) {
872 //
873 // Now we know how many EFI_INPUT_KEY structs we need to attach to the end of the EFI_KEY_OPTION struct.
874 // Re-allocate with the added information.
875 //
876 KeyOptionBuffer = AllocateCopyPool(sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount), &NewKeyOption);
877 if (KeyOptionBuffer == NULL) {
878 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
879 ShellStatus = SHELL_OUT_OF_RESOURCES;
880 }
881 }
882 for (LoopCounter = 0 ; ShellStatus == SHELL_SUCCESS && LoopCounter < NewKeyOption.KeyData.Options.InputKeyCount; LoopCounter++) {
883 //
884 // ScanCode
885 //
886 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
887 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate) || StrStr(Walker, L" ") == NULL) {
888 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
889 ShellStatus = SHELL_INVALID_PARAMETER;
890 }
891 ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].ScanCode = (UINT16)Intermediate;
892 Temp = StrStr(Walker, L" ");
893 if (Temp != NULL) {
894 Walker = Temp;
895 }
896 while(Walker[0] == L' ') {
897 Walker++;
898 }
899
900 //
901 // UnicodeChar
902 //
903 Status = ShellConvertStringToUint64(Walker, &Intermediate, FALSE, TRUE);
904 if (EFI_ERROR(Status) || (((UINT16)Intermediate) != Intermediate)) {
905 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", Walker);
906 ShellStatus = SHELL_INVALID_PARAMETER;
907 }
908 ((EFI_INPUT_KEY*)(((UINT8*)KeyOptionBuffer) + sizeof(EFI_KEY_OPTION)))[LoopCounter].UnicodeChar = (UINT16)Intermediate;
909 Temp = StrStr(Walker, L" ");
910 if (Temp != NULL) {
911 Walker = Temp;
912 }
913 while(Walker[0] == L' ') {
914 Walker++;
915 }
916 }
917
918 if (ShellStatus == SHELL_SUCCESS) {
919 //
920 // Now do the BootOption / BootOptionCrc
921 //
922 ASSERT (OptionIndex <= OrderCount);
923 KeyOptionBuffer->BootOption = CurrentOrder[OptionIndex];
924 Status = GetBootOptionCrc(&(KeyOptionBuffer->BootOptionCrc), KeyOptionBuffer->BootOption);
925 if (EFI_ERROR(Status)) {
926 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"Option Index");
927 ShellStatus = SHELL_INVALID_PARAMETER;
928 }
929 }
930
931 if (ShellStatus == SHELL_SUCCESS) {
932 for (Temp2 = NULL, KeyIndex = 0 ; KeyIndex <= 0xFFFF ; KeyIndex++) {
933 UnicodeSPrint(VariableName, sizeof(VariableName), L"Key%04x", KeyIndex);
934 Status = GetEfiGlobalVariable2 (VariableName, &VariableData, NULL);
935 if (Status == EFI_NOT_FOUND) {
936 break;
937 }
938 if (!EFI_ERROR(Status)) {
939 SHELL_FREE_NON_NULL(VariableData);
940 }
941 }
942 if (KeyIndex <= 0xFFFF) {
943 Status = gRT->SetVariable(
944 VariableName,
945 (EFI_GUID*)&gEfiGlobalVariableGuid,
946 EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS,
947 sizeof(EFI_KEY_OPTION) + (sizeof(EFI_INPUT_KEY) * NewKeyOption.KeyData.Options.InputKeyCount),
948 KeyOptionBuffer);
949 if (EFI_ERROR(Status)) {
950 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
951 ShellStatus = SHELL_INVALID_PARAMETER;
952 }
953 } else {
954 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_VAR_NO_NUM), gShellBcfgHiiHandle, L"bcfg");
955 ShellStatus = SHELL_INVALID_PARAMETER;
956 }
957 ASSERT(FileName == NULL && Data == NULL);
958 }
959 }
960 }
961
962 //
963 // Shouldn't be possible to have have both. Neither is ok though.
964 //
965 ASSERT(FileName == NULL || Data == NULL);
966
967 if (ShellStatus == SHELL_SUCCESS && (FileName != NULL || Data != NULL)) {
968 if (FileName != NULL) {
969 //
970 // Open the file and populate the data buffer.
971 //
972 Status = ShellOpenFileByName(
973 FileName,
974 &FileHandle,
975 EFI_FILE_MODE_READ,
976 0);
977 if (!EFI_ERROR(Status)) {
978 Status = ShellGetFileSize(FileHandle, &Intermediate);
979 }
980 Data = AllocateZeroPool((UINTN)Intermediate);
981 if (Data == NULL) {
982 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellBcfgHiiHandle, L"bcfg");
983 ShellStatus = SHELL_OUT_OF_RESOURCES;
984 }
985 if (!EFI_ERROR(Status)) {
986 Status = ShellReadFile(FileHandle, (UINTN *)&Intermediate, Data);
987 }
988 } else {
989 Intermediate = StrSize(Data);
990 }
991
992 if (!EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS && Data != NULL) {
993 Status = UpdateOptionalData(CurrentOrder[OptionIndex], (UINTN)Intermediate, (UINT8*)Data, Target);
994 if (EFI_ERROR(Status)) {
995 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
996 ShellStatus = SHELL_INVALID_PARAMETER;
997 }
998 }
999 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
1000 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_SET_VAR_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
1001 ShellStatus = SHELL_INVALID_PARAMETER;
1002 }
1003 }
1004
1005 SHELL_FREE_NON_NULL(Data);
1006 SHELL_FREE_NON_NULL(KeyOptionBuffer);
1007 SHELL_FREE_NON_NULL(FileName);
1008 return ShellStatus;
1009 }
1010
1011 /**
1012 Function to dump the Bcfg information.
1013
1014 @param[in] Op The operation.
1015 @param[in] OrderCount How many to dump.
1016 @param[in] CurrentOrder The pointer to the current order of items.
1017 @param[in] VerboseOutput TRUE for extra output. FALSE otherwise.
1018
1019 @retval SHELL_SUCCESS The dump was successful.
1020 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
1021 **/
1022 SHELL_STATUS
BcfgDisplayDump(IN CONST CHAR16 * Op,IN CONST UINTN OrderCount,IN CONST UINT16 * CurrentOrder,IN CONST BOOLEAN VerboseOutput)1023 BcfgDisplayDump(
1024 IN CONST CHAR16 *Op,
1025 IN CONST UINTN OrderCount,
1026 IN CONST UINT16 *CurrentOrder,
1027 IN CONST BOOLEAN VerboseOutput
1028 )
1029 {
1030 EFI_STATUS Status;
1031 UINT8 *Buffer;
1032 UINTN BufferSize;
1033 CHAR16 VariableName[12];
1034 UINTN LoopVar;
1035 CHAR16 *DevPathString;
1036 VOID *FilePathList;
1037 UINTN Errors;
1038 EFI_LOAD_OPTION *LoadOption;
1039 CHAR16 *Description;
1040 UINTN DescriptionSize;
1041 UINTN OptionalDataOffset;
1042
1043 if (OrderCount == 0) {
1044 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_BCFG_NONE), gShellBcfgHiiHandle, L"bcfg");
1045 return (SHELL_SUCCESS);
1046 }
1047
1048 Errors = 0;
1049
1050 for (LoopVar = 0 ; LoopVar < OrderCount ; LoopVar++) {
1051 Buffer = NULL;
1052 BufferSize = 0;
1053 DevPathString = NULL;
1054
1055 UnicodeSPrint(VariableName, sizeof(VariableName), L"%s%04x", Op, CurrentOrder[LoopVar]);
1056
1057 Status = gRT->GetVariable(
1058 VariableName,
1059 (EFI_GUID*)&gEfiGlobalVariableGuid,
1060 NULL,
1061 &BufferSize,
1062 Buffer);
1063 if (Status == EFI_BUFFER_TOO_SMALL) {
1064 Buffer = AllocateZeroPool(BufferSize);
1065 Status = gRT->GetVariable(
1066 VariableName,
1067 (EFI_GUID*)&gEfiGlobalVariableGuid,
1068 NULL,
1069 &BufferSize,
1070 Buffer);
1071 }
1072
1073 if (EFI_ERROR(Status) || Buffer == NULL) {
1074 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_READ_FAIL), gShellBcfgHiiHandle, L"bcfg", VariableName);
1075 ++Errors;
1076 goto Cleanup;
1077 }
1078
1079 //
1080 // We expect the Attributes, FilePathListLength, and L'\0'-terminated
1081 // Description fields to be present.
1082 //
1083 if (BufferSize < sizeof *LoadOption + sizeof (CHAR16)) {
1084 ShellPrintHiiEx (
1085 -1,
1086 -1,
1087 NULL,
1088 STRING_TOKEN (STR_BCFG_VAR_CORRUPT),
1089 gShellBcfgHiiHandle,
1090 L"bcfg",
1091 VariableName
1092 );
1093 ++Errors;
1094 goto Cleanup;
1095 }
1096
1097 LoadOption = (EFI_LOAD_OPTION *)Buffer;
1098 Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
1099 DescriptionSize = StrSize (Description);
1100
1101 if (LoadOption->FilePathListLength != 0) {
1102 FilePathList = (UINT8 *)Description + DescriptionSize;
1103 DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
1104 }
1105
1106 OptionalDataOffset = sizeof *LoadOption + DescriptionSize +
1107 LoadOption->FilePathListLength;
1108
1109 ShellPrintHiiEx(
1110 -1,
1111 -1,
1112 NULL,
1113 STRING_TOKEN(STR_BCFG_LOAD_OPTIONS),
1114 gShellBcfgHiiHandle,
1115 LoopVar,
1116 VariableName,
1117 Description,
1118 DevPathString,
1119 OptionalDataOffset >= BufferSize ? L'N' : L'Y'
1120 );
1121 if (VerboseOutput && (OptionalDataOffset < BufferSize)) {
1122 DumpHex (
1123 2, // Indent
1124 0, // Offset (displayed)
1125 BufferSize - OptionalDataOffset, // DataSize
1126 Buffer + OptionalDataOffset // UserData
1127 );
1128 }
1129
1130 Cleanup:
1131 if (Buffer != NULL) {
1132 FreePool(Buffer);
1133 }
1134 if (DevPathString != NULL) {
1135 FreePool(DevPathString);
1136 }
1137 }
1138 return (Errors > 0) ? SHELL_INVALID_PARAMETER : SHELL_SUCCESS;
1139 }
1140
1141 /**
1142 Function to initialize the BCFG operation structure.
1143
1144 @param[in] Struct The stuct to initialize.
1145 **/
1146 VOID
InitBcfgStruct(IN BGFG_OPERATION * Struct)1147 InitBcfgStruct(
1148 IN BGFG_OPERATION *Struct
1149 )
1150 {
1151 ASSERT(Struct != NULL);
1152 Struct->Target = BcfgTargetMax;
1153 Struct->Type = BcfgTypeMax;
1154 Struct->Number1 = 0;
1155 Struct->Number2 = 0;
1156 Struct->HandleIndex = 0;
1157 Struct->FileName = NULL;
1158 Struct->Description = NULL;
1159 Struct->Order = NULL;
1160 Struct->OptData = NULL;
1161 }
1162
1163
1164 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
1165 {L"-v", TypeFlag},
1166 {L"-opt", TypeMaxValue},
1167 {NULL, TypeMax}
1168 };
1169
1170 /**
1171 Function for 'bcfg' command.
1172
1173 @param[in] ImageHandle Handle to the Image (NULL if Internal).
1174 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
1175 **/
1176 SHELL_STATUS
1177 EFIAPI
ShellCommandRunBcfg(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1178 ShellCommandRunBcfg (
1179 IN EFI_HANDLE ImageHandle,
1180 IN EFI_SYSTEM_TABLE *SystemTable
1181 )
1182 {
1183 EFI_STATUS Status;
1184 LIST_ENTRY *Package;
1185 CHAR16 *ProblemParam;
1186 SHELL_STATUS ShellStatus;
1187 UINTN ParamNumber;
1188 CONST CHAR16 *CurrentParam;
1189 BGFG_OPERATION CurrentOperation;
1190 UINTN Length;
1191 UINT64 Intermediate;
1192 UINT16 Count;
1193
1194 Length = 0;
1195 ProblemParam = NULL;
1196 Package = NULL;
1197 ShellStatus = SHELL_SUCCESS;
1198
1199 InitBcfgStruct(&CurrentOperation);
1200
1201 //
1202 // initialize the shell lib (we must be in non-auto-init...)
1203 //
1204 Status = ShellInitialize();
1205 ASSERT_EFI_ERROR(Status);
1206
1207 Status = CommandInit();
1208 ASSERT_EFI_ERROR(Status);
1209
1210 //
1211 // parse the command line
1212 //
1213 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
1214 if (EFI_ERROR(Status)) {
1215 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
1216 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellBcfgHiiHandle, L"bcfg", ProblemParam);
1217 FreePool(ProblemParam);
1218 ShellStatus = SHELL_INVALID_PARAMETER;
1219 } else {
1220 ASSERT(FALSE);
1221 }
1222 } else {
1223 //
1224 // Read in if we are doing -OPT
1225 //
1226 if (ShellCommandLineGetFlag(Package, L"-opt")) {
1227 CurrentOperation.OptData = ShellCommandLineGetValue(Package, L"-opt");
1228 if (CurrentOperation.OptData == NULL) {
1229 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellBcfgHiiHandle, L"bcfg", L"-opt");
1230 ShellStatus = SHELL_INVALID_PARAMETER;
1231 }
1232 CurrentOperation.Type = BcfgTypeOpt;
1233 }
1234
1235 //
1236 // small block to read the target of the operation
1237 //
1238 if ((ShellCommandLineGetCount(Package) < 3 && CurrentOperation.Type != BcfgTypeOpt) ||
1239 (ShellCommandLineGetCount(Package) < 2 && CurrentOperation.Type == BcfgTypeOpt)
1240 ){
1241 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1242 ShellStatus = SHELL_INVALID_PARAMETER;
1243 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"driver") == 0) {
1244 CurrentOperation.Target = BcfgTargetDriverOrder;
1245 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)ShellCommandLineGetRawValue(Package, 1), L"boot") == 0) {
1246 CurrentOperation.Target = BcfgTargetBootOrder;
1247 } else {
1248 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_DRIVER_BOOT), gShellBcfgHiiHandle, L"bcfg");
1249 ShellStatus = SHELL_INVALID_PARAMETER;
1250 }
1251
1252
1253 //
1254 // Read in the boot or driver order environment variable (not needed for opt)
1255 //
1256 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
1257 Length = 0;
1258 Status = gRT->GetVariable(
1259 CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
1260 (EFI_GUID*)&gEfiGlobalVariableGuid,
1261 NULL,
1262 &Length,
1263 CurrentOperation.Order);
1264 if (Status == EFI_BUFFER_TOO_SMALL) {
1265 CurrentOperation.Order = AllocateZeroPool(Length+(4*sizeof(CurrentOperation.Order[0])));
1266 if (CurrentOperation.Order == NULL) {
1267 ShellStatus = SHELL_OUT_OF_RESOURCES;
1268 } else {
1269 Status = gRT->GetVariable(
1270 CurrentOperation.Target == BcfgTargetBootOrder?(CHAR16*)L"BootOrder":(CHAR16*)L"DriverOrder",
1271 (EFI_GUID*)&gEfiGlobalVariableGuid,
1272 NULL,
1273 &Length,
1274 CurrentOperation.Order);
1275 }
1276 }
1277 }
1278
1279 Count = (UINT16) (Length / sizeof(CurrentOperation.Order[0]));
1280
1281 //
1282 // large block to read the type of operation and verify parameter types for the info.
1283 //
1284 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax) {
1285 for (ParamNumber = 2 ; ParamNumber < ShellCommandLineGetCount(Package) && ShellStatus == SHELL_SUCCESS; ParamNumber++) {
1286 CurrentParam = ShellCommandLineGetRawValue(Package, ParamNumber);
1287 if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"dump") == 0) {
1288 CurrentOperation.Type = BcfgTypeDump;
1289 if (ShellCommandLineGetCount(Package) > 3) {
1290 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellBcfgHiiHandle, L"bcfg");
1291 ShellStatus = SHELL_INVALID_PARAMETER;
1292 }
1293 } else if (ShellCommandLineGetFlag(Package, L"-v")) {
1294 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", L"-v (without dump)");
1295 ShellStatus = SHELL_INVALID_PARAMETER;
1296 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"add") == 0) {
1297 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1298 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1299 ShellStatus = SHELL_INVALID_PARAMETER;
1300 }
1301 CurrentOperation.Type = BcfgTypeAdd;
1302 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1303 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1304 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1305 ShellStatus = SHELL_INVALID_PARAMETER;
1306 } else {
1307 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1308 CurrentOperation.Number1 = (UINT16)Intermediate;
1309 ASSERT(CurrentOperation.FileName == NULL);
1310 CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1311 ASSERT(CurrentOperation.Description == NULL);
1312 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1313 }
1314 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addp") == 0) {
1315 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1316 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1317 ShellStatus = SHELL_INVALID_PARAMETER;
1318 }
1319 CurrentOperation.Type = BcfgTypeAddp;
1320 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1321 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1322 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1323 ShellStatus = SHELL_INVALID_PARAMETER;
1324 } else {
1325 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1326 CurrentOperation.Number1 = (UINT16)Intermediate;
1327 ASSERT(CurrentOperation.FileName == NULL);
1328 CurrentOperation.FileName = StrnCatGrow(&CurrentOperation.FileName , NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1329 ASSERT(CurrentOperation.Description == NULL);
1330 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1331 }
1332 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"addh") == 0) {
1333 if ((ParamNumber + 3) >= ShellCommandLineGetCount(Package)) {
1334 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1335 ShellStatus = SHELL_INVALID_PARAMETER;
1336 }
1337 CurrentOperation.Type = BcfgTypeAddh;
1338 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1339 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1340 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1341 ShellStatus = SHELL_INVALID_PARAMETER;
1342 } else {
1343 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1344 CurrentOperation.Number1 = (UINT16)Intermediate;
1345 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1346 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1347 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1348 ShellStatus = SHELL_INVALID_PARAMETER;
1349 } else {
1350 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1351 CurrentOperation.HandleIndex = (UINT16)Intermediate;
1352 ASSERT(CurrentOperation.Description == NULL);
1353 CurrentOperation.Description = StrnCatGrow(&CurrentOperation.Description, NULL, ShellCommandLineGetRawValue(Package, ++ParamNumber), 0);
1354 }
1355 }
1356 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"rm") == 0) {
1357 if ((ParamNumber + 1) >= ShellCommandLineGetCount(Package)) {
1358 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1359 ShellStatus = SHELL_INVALID_PARAMETER;
1360 }
1361 CurrentOperation.Type = BcfgTypeRm;
1362 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1363 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1364 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1365 ShellStatus = SHELL_INVALID_PARAMETER;
1366 } else {
1367 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1368 CurrentOperation.Number1 = (UINT16)Intermediate;
1369 if (CurrentOperation.Number1 >= Count){
1370 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1371 ShellStatus = SHELL_INVALID_PARAMETER;
1372 }
1373 }
1374 } else if (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)CurrentParam, L"mv") == 0) {
1375 if ((ParamNumber + 2) >= ShellCommandLineGetCount(Package)) {
1376 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellBcfgHiiHandle, L"bcfg");
1377 ShellStatus = SHELL_INVALID_PARAMETER;
1378 }
1379 CurrentOperation.Type = BcfgTypeMv;
1380 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1381 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1382 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1383 ShellStatus = SHELL_INVALID_PARAMETER;
1384 } else {
1385 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1386 CurrentOperation.Number1 = (UINT16)Intermediate;
1387 if (CurrentOperation.Number1 >= Count){
1388 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1389 ShellStatus = SHELL_INVALID_PARAMETER;
1390 } else {
1391 CurrentParam = ShellCommandLineGetRawValue(Package, ++ParamNumber);
1392 if (CurrentParam == NULL || !ShellIsHexOrDecimalNumber(CurrentParam, TRUE, FALSE)) {
1393 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1394 ShellStatus = SHELL_INVALID_PARAMETER;
1395 } else {
1396 Status = ShellConvertStringToUint64(CurrentParam, &Intermediate, TRUE, FALSE);
1397 CurrentOperation.Number2 = (UINT16)Intermediate;
1398 }
1399 if (CurrentOperation.Number2 == CurrentOperation.Number1
1400 ||CurrentOperation.Number2 >= Count
1401 ){
1402 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_BCFG_NUMB_RANGE), gShellBcfgHiiHandle, L"bcfg", Count);
1403 ShellStatus = SHELL_INVALID_PARAMETER;
1404 }
1405 }
1406 }
1407 } else {
1408 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellBcfgHiiHandle, L"bcfg", CurrentParam);
1409 ShellStatus = SHELL_INVALID_PARAMETER;
1410 }
1411 }
1412 }
1413 if (ShellStatus == SHELL_SUCCESS && CurrentOperation.Target < BcfgTargetMax && CurrentOperation.Type < BcfgTypeMax) {
1414 //
1415 // we have all the info. Do the work
1416 //
1417 switch (CurrentOperation.Type) {
1418 case BcfgTypeDump:
1419 ShellStatus = BcfgDisplayDump(
1420 CurrentOperation.Target == BcfgTargetBootOrder?L"Boot":L"Driver",
1421 Count,
1422 CurrentOperation.Order,
1423 ShellCommandLineGetFlag(Package, L"-v"));
1424 break;
1425 case BcfgTypeMv:
1426 ShellStatus = BcfgMove(
1427 CurrentOperation.Target,
1428 CurrentOperation.Order,
1429 Count,
1430 CurrentOperation.Number1,
1431 CurrentOperation.Number2);
1432 break;
1433 case BcfgTypeRm:
1434 ShellStatus = BcfgRemove(
1435 CurrentOperation.Target,
1436 CurrentOperation.Order,
1437 Count,
1438 CurrentOperation.Number1);
1439 break;
1440 case BcfgTypeAdd:
1441 case BcfgTypeAddp:
1442 case BcfgTypeAddh:
1443 ShellStatus = BcfgAdd(
1444 CurrentOperation.Number1,
1445 CurrentOperation.FileName,
1446 CurrentOperation.Description==NULL?L"":CurrentOperation.Description,
1447 CurrentOperation.Order,
1448 Count,
1449 CurrentOperation.Target,
1450 (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddh),
1451 (BOOLEAN)(CurrentOperation.Type == BcfgTypeAddp),
1452 CurrentOperation.HandleIndex);
1453 break;
1454 case BcfgTypeOpt:
1455 ShellStatus = BcfgAddOpt(
1456 CurrentOperation.OptData,
1457 CurrentOperation.Order,
1458 Count,
1459 CurrentOperation.Target);
1460 break;
1461 default:
1462 ASSERT(FALSE);
1463 }
1464 }
1465 }
1466
1467 if (Package != NULL) {
1468 ShellCommandLineFreeVarList (Package);
1469 }
1470 if (CurrentOperation.FileName != NULL) {
1471 FreePool(CurrentOperation.FileName);
1472 }
1473 if (CurrentOperation.Description != NULL) {
1474 FreePool(CurrentOperation.Description);
1475 }
1476 if (CurrentOperation.Order != NULL) {
1477 FreePool(CurrentOperation.Order);
1478 }
1479
1480 return (ShellStatus);
1481 }
1482
1483
1484 /**
1485 Function to get the filename with help context if HII will not be used.
1486
1487 @return The filename with help text in it.
1488 **/
1489 CONST CHAR16*
1490 EFIAPI
ShellCommandGetManFileNameBcfg(VOID)1491 ShellCommandGetManFileNameBcfg (
1492 VOID
1493 )
1494 {
1495 return (mFileName);
1496 }
1497
1498 /**
1499 "Constructor" for the library.
1500
1501 This will register the handler for the bcfg command.
1502
1503 @param[in] ImageHandle the image handle of the process
1504 @param[in] SystemTable the EFI System Table pointer
1505 @param[in] Name the profile name to use
1506
1507 @retval EFI_SUCCESS the shell command handlers were installed sucessfully
1508 @retval EFI_UNSUPPORTED the shell level required was not found.
1509 **/
1510 EFI_STATUS
1511 EFIAPI
BcfgLibraryRegisterBcfgCommand(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable,IN CONST CHAR16 * Name)1512 BcfgLibraryRegisterBcfgCommand (
1513 IN EFI_HANDLE ImageHandle,
1514 IN EFI_SYSTEM_TABLE *SystemTable,
1515 IN CONST CHAR16 *Name
1516 )
1517 {
1518 if (gShellBcfgHiiHandle != NULL) {
1519 return (EFI_SUCCESS);
1520 }
1521
1522 gShellBcfgHiiHandle = HiiAddPackages (&gShellBcfgHiiGuid, gImageHandle, UefiShellBcfgCommandLibStrings, NULL);
1523 if (gShellBcfgHiiHandle == NULL) {
1524 return (EFI_DEVICE_ERROR);
1525 }
1526
1527 //
1528 // install our shell command handler
1529 //
1530 ShellCommandRegisterCommandName(L"bcfg", ShellCommandRunBcfg , ShellCommandGetManFileNameBcfg, 0, Name, FALSE, gShellBcfgHiiHandle, STRING_TOKEN(STR_GET_HELP_BCFG));
1531
1532 return (EFI_SUCCESS);
1533 }
1534
1535 /**
1536 Destructor for the library. free any resources.
1537
1538 @param ImageHandle The image handle of the process.
1539 @param SystemTable The EFI System Table pointer.
1540 **/
1541 EFI_STATUS
1542 EFIAPI
BcfgLibraryUnregisterBcfgCommand(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1543 BcfgLibraryUnregisterBcfgCommand (
1544 IN EFI_HANDLE ImageHandle,
1545 IN EFI_SYSTEM_TABLE *SystemTable
1546 )
1547 {
1548 if (gShellBcfgHiiHandle != NULL) {
1549 HiiRemovePackages(gShellBcfgHiiHandle);
1550 }
1551 gShellBcfgHiiHandle = NULL;
1552 return (EFI_SUCCESS);
1553 }
1554
1555