is NULL, then the current shell environment is used.\r
@param StatusCode Points to the status code returned by the command.\r
\r
+ @param[out] ExitDataSize ExitDataSize as returned from gBS->StartImage\r
+ @param[out] ExitData ExitData as returned from gBS->StartImage\r
+\r
@retval EFI_SUCCESS The command executed successfully. The status code\r
returned by the command is pointed to by StatusCode.\r
@retval EFI_INVALID_PARAMETER The parameters are invalid.\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
IN CONST CHAR16 *CommandLine OPTIONAL,\r
IN CONST CHAR16 **Environment OPTIONAL,\r
- OUT EFI_STATUS *StatusCode OPTIONAL\r
+ OUT UINTN *ExitDataSize OPTIONAL,\r
+ OUT CHAR16 **ExitData OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
+ EFI_STATUS CleanupStatus;\r
EFI_HANDLE NewHandle;\r
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
LIST_ENTRY OrigEnvs;\r
EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
+ UINTN InternalExitDataSize;\r
+ UINTN *ExitDataSizePtr;\r
+\r
+ // ExitDataSize is not OPTIONAL for gBS->BootServices, provide somewhere for\r
+ // it to be dumped if the caller doesn't want it.\r
+ if (ExitData == NULL) {\r
+ ExitDataSizePtr = &InternalExitDataSize;\r
+ } else {\r
+ ExitDataSizePtr = ExitDataSize;\r
+ }\r
\r
if (ParentImageHandle == NULL) {\r
return (EFI_INVALID_PARAMETER);\r
///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
\r
//\r
- // now start the image and if the caller wanted the return code pass it to them...\r
+ // now start the image, passing up exit data if the caller requested it\r
//\r
if (!EFI_ERROR(Status)) {\r
- if (StatusCode != NULL) {\r
- *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);\r
- } else {\r
- Status = gBS->StartImage(NewHandle, NULL, NULL);\r
- }\r
+ Status = gBS->StartImage(\r
+ NewHandle,\r
+ ExitDataSizePtr,\r
+ ExitData\r
+ );\r
}\r
\r
//\r
// Cleanup (and dont overwrite errors)\r
//\r
if (EFI_ERROR(Status)) {\r
- gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
+ CleanupStatus = gBS->UninstallProtocolInterface(\r
+ NewHandle,\r
+ &gEfiShellParametersProtocolGuid,\r
+ &ShellParamsProtocol\r
+ );\r
+ ASSERT_EFI_ERROR(CleanupStatus);\r
} else {\r
- Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
- ASSERT_EFI_ERROR(Status);\r
+ CleanupStatus = gBS->UninstallProtocolInterface(\r
+ NewHandle,\r
+ &gEfiShellParametersProtocolGuid,\r
+ &ShellParamsProtocol\r
+ );\r
+ ASSERT_EFI_ERROR(CleanupStatus);\r
}\r
}\r
\r
if (!IsListEmpty(&OrigEnvs)) {\r
if (EFI_ERROR(Status)) {\r
- SetEnvironmentVariableList(&OrigEnvs);\r
+ CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+ ASSERT_EFI_ERROR(CleanupStatus);\r
} else {\r
- Status = SetEnvironmentVariableList(&OrigEnvs);\r
+ CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+ ASSERT_EFI_ERROR (CleanupStatus);\r
}\r
}\r
\r
CHAR16 *Temp;\r
EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
UINTN Size;\r
+ UINTN ExitDataSize;\r
+ CHAR16 *ExitData;\r
\r
if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
return (EFI_UNSUPPORTED);\r
DevPath,\r
Temp,\r
(CONST CHAR16**)Environment,\r
- StatusCode);\r
+ &ExitDataSize,\r
+ &ExitData);\r
+\r
+ if (Status == EFI_ABORTED) {\r
+ // If the command exited with an error, the shell should put the exit\r
+ // status in ExitData, preceded by a null-terminated string.\r
+ ASSERT (ExitDataSize == StrSize (ExitData) + sizeof (SHELL_STATUS));\r
+\r
+ if (StatusCode != NULL) {\r
+ // Skip the null-terminated string\r
+ ExitData += StrLen (ExitData) + 1;\r
+\r
+ // Use CopyMem to avoid alignment faults\r
+ CopyMem (StatusCode, ExitData, sizeof (SHELL_STATUS));\r
+\r
+ // Convert from SHELL_STATUS to EFI_STATUS\r
+ // EFI_STATUSes have top bit set when they are errors.\r
+ // (See UEFI Spec Appendix D)\r
+ if (*StatusCode != SHELL_SUCCESS) {\r
+ *StatusCode = (EFI_STATUS) *StatusCode | MAX_BIT;\r
+ }\r
+ }\r
+ FreePool (ExitData);\r
+ Status = EFI_SUCCESS;\r
+ } else if ((StatusCode != NULL) && !EFI_ERROR(Status)) {\r
+ *StatusCode = EFI_SUCCESS;\r
+ }\r
\r
//\r
// de-allocate and return\r
InternalFreeShellFileInfoNode(ShellFileListItem);\r
}\r
InternalFreeShellFileInfoNode(*FileList);\r
+ *FileList = NULL;\r
return(EFI_SUCCESS);\r
}\r
\r