MdeModulePkg/UefiBootManagerLib: limit recursive call depth

Function BmRepairAllControllers may recursively call itself if some
driver health protocol returns EfiDriverHealthStatusReconnectRequired.
However, driver health protocol of some buggy third party driver may
always return such status even after one and another reconnect. The
endless iteration will cause stack overflow and then system exception,
and it may be not easy to find that the exception is actually caused
by stack overflow.

So we limit the number of reconnect retry to 10 to improve code
robustness, and DEBUG_CODE is moved ahead before recursive repair to
track the repair result.

We also remove a duplicated declaration of BmRepairAllControllers() in
InternalBm.h in this patch, for it is only a trivial change.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Heyi Guo <heyi.guo@linaro.org>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Heyi Guo 2018-03-01 10:39:32 +08:00 committed by Ruiyu Ni
parent 61c1742ba1
commit 72208a9a90
3 changed files with 24 additions and 15 deletions

View File

@ -1767,7 +1767,7 @@ EfiBootManagerBoot (
// //
// 4. Repair system through DriverHealth protocol // 4. Repair system through DriverHealth protocol
// //
BmRepairAllControllers (); BmRepairAllControllers (0);
} }
PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber); PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);

View File

@ -423,10 +423,13 @@ EfiBootManagerFreeDriverHealthInfo (
/** /**
Repair all the controllers according to the Driver Health status queried. Repair all the controllers according to the Driver Health status queried.
@param ReconnectRepairCount To record the number of recursive call of
this function itself.
**/ **/
VOID VOID
BmRepairAllControllers ( BmRepairAllControllers (
VOID UINTN ReconnectRepairCount
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -548,10 +551,6 @@ BmRepairAllControllers (
EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count); EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
if (ReconnectRequired) {
BmRepairAllControllers ();
}
DEBUG_CODE ( DEBUG_CODE (
CHAR16 *ControllerName; CHAR16 *ControllerName;
@ -576,6 +575,15 @@ BmRepairAllControllers (
EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count); EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
); );
if (ReconnectRequired) {
if (ReconnectRepairCount < MAX_RECONNECT_REPAIR) {
BmRepairAllControllers (ReconnectRepairCount + 1);
} else {
DEBUG ((DEBUG_ERROR, "[%a:%d] Repair failed after %d retries.\n",
__FUNCTION__, __LINE__, ReconnectRepairCount));
}
}
if (RebootRequired) { if (RebootRequired) {
DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n")); DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));
gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);

View File

@ -108,6 +108,12 @@ CHAR16 *
#define BM_OPTION_NAME_LEN sizeof ("PlatformRecovery####") #define BM_OPTION_NAME_LEN sizeof ("PlatformRecovery####")
extern CHAR16 *mBmLoadOptionName[]; extern CHAR16 *mBmLoadOptionName[];
//
// Maximum number of reconnect retry to repair controller; it is to limit the
// number of recursive call of BmRepairAllControllers.
//
#define MAX_RECONNECT_REPAIR 10
/** /**
Visitor function to be called by BmForEachVariable for each variable Visitor function to be called by BmForEachVariable for each variable
in variable storage. in variable storage.
@ -145,10 +151,13 @@ typedef struct {
/** /**
Repair all the controllers according to the Driver Health status queried. Repair all the controllers according to the Driver Health status queried.
@param ReconnectRepairCount To record the number of recursive call of
this function itself.
**/ **/
VOID VOID
BmRepairAllControllers ( BmRepairAllControllers (
VOID UINTN ReconnectRepairCount
); );
#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k') #define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
@ -327,14 +336,6 @@ BmDelPartMatchInstance (
IN EFI_DEVICE_PATH_PROTOCOL *Single IN EFI_DEVICE_PATH_PROTOCOL *Single
); );
/**
Repair all the controllers according to the Driver Health status queried.
**/
VOID
BmRepairAllControllers (
VOID
);
/** /**
Print the device path info. Print the device path info.