Laszlo,

Your updating patch looks better. But when I tried it on my platform, Sometime, 
it hang at syncing MTRRs from BSP to Aps. I am investigating it and will 
feedback you later.

Thanks!
Jeff

-----Original Message-----
From: Laszlo Ersek [mailto:[email protected]] 
Sent: Wednesday, October 28, 2015 8:16 PM
To: Fan, Jeff; [email protected]
Cc: Kinney, Michael D; Justen, Jordan L; Chen Fan
Subject: Re: [Patch 2/2] UefiCpuPkg/CpuDxe: Fix one dead lock issue in 
ProcessorToIdleState()

On 10/28/15 07:42, Jeff Fan wrote:
> There is one dead lock issue between BSP and AP. AP has one logic to 
> enter into Sleep state (hlt) if it found its state is Idle state in one loop.
> In ProcessorToIdleState() function, AP will get current AP state, if 
> its state is Sleep state, then it will go into real sleep(hlt) state.
> The dead lock may happen if BSP found AP state is Sleep state and send 
> INIT-SIPI -SIPI to AP. But AP just acquried the lock to get its state. 
> If AP is reset, the lock will not released correctly.
> This fix is to let AP enter into real sleep(hlt) state immediately 
> after it changes its state is set to Sleep and needn't get lock again.
> 
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jeff Fan <[email protected]>
> Cc: Michael Kinney <[email protected]>
> Cc: Jordan Justen <[email protected]>
> Cc: Laszlo Ersek <[email protected]>
> Cc: Chen Fan <[email protected]>
> ---
>  UefiCpuPkg/CpuDxe/CpuMp.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c 
> index 3de2aa5..357ee42 100644
> --- a/UefiCpuPkg/CpuDxe/CpuMp.c
> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c
> @@ -1289,14 +1289,18 @@ ProcessorToIdleState (
>        GetMpSpinLock (CpuData);
>        if (CpuData->State == CpuStateIdle) {
>            CpuData->State = CpuStateSleeping;
> +        ReleaseMpSpinLock (CpuData);
> +        while (TRUE) {
> +          //
> +          // Place AP into cli-hlt loop to handle RSM from SMM case
> +          //
> +          DisableInterrupts ();
> +          CpuSleep ();
> +        }
>        }
>        ReleaseMpSpinLock (CpuData);
>      }
>  
> -    if (GetApState (CpuData) == CpuStateSleeping) {
> -      CpuSleep ();
> -    }
> -
>      CpuPause ();
>    }
>  
> 

I think the idea in this patch is good, but I recommend a *much* more sweeping 
change for this function. From my past multi-threaded programming experience, 
it is always best to hold the lock *by default* in a critical section, and only 
release it *temporarily* while yielding, or invoking a callback, or invoking a 
blocking operation.

- It makes no sense to release and reacquire a mutex or splinlock if our thread 
or CPU has actual, fast work to do, without wanting to yield intentionally.

- For loops especially, this means that the loop body is both *entered* and 
*exited* with the lock held.

- This approach tends to improve throughput and happens to eliminate a *bunch* 
of TOCTTOU races.

Therefore my proposal would be:

> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c 
> index 98976a1..31c6222 100644
> --- a/UefiCpuPkg/CpuDxe/CpuMp.c
> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c
> @@ -1288,40 +1288,42 @@ ProcessorToIdleState (
>      CpuData->Procedure = NULL;
>    }
>    CpuData->State = CpuStateIdle;
> -  ReleaseMpSpinLock (CpuData);
>  
>    while (TRUE) {
> -    GetMpSpinLock (CpuData);
>      ProcedureArgument = CpuData->Parameter;
>      Procedure = CpuData->Procedure;
> -    ReleaseMpSpinLock (CpuData);
>  
>      if (Procedure != NULL) {
> -      SetApState (CpuData, CpuStateBusy);
> +      CpuData->State = CpuStateBusy;
> +      ReleaseMpSpinLock (CpuData);
>  
>        Procedure ((VOID*) ProcedureArgument);
>  
>        GetMpSpinLock (CpuData);
>        CpuData->Procedure = NULL;
>        CpuData->State = CpuStateFinished;
> -      ReleaseMpSpinLock (CpuData);
>      } else {
>        //
>        // if no procedure to execution, we simply put AP
>        // into sleeping state, and waiting BSP sent SIPI.
>        //
> -      GetMpSpinLock (CpuData);
>        if (CpuData->State == CpuStateIdle) {
> -          CpuData->State = CpuStateSleeping;
> +        CpuData->State = CpuStateSleeping;
> +        ReleaseMpSpinLock (CpuData);
> +
> +        //
> +        // wait for INIT-SIPI-SIPI
> +        //
> +        while (TRUE) {
> +          DisableInterrupts ();
> +          CpuSleep ();
> +        }
>        }
> -      ReleaseMpSpinLock (CpuData);
> -    }
> -
> -    if (GetApState (CpuData) == CpuStateSleeping) {
> -      CpuSleep ();
>      }
>  
> +    ReleaseMpSpinLock (CpuData);
>      CpuPause ();
> +    GetMpSpinLock (CpuData);
>    }
>  
>    CpuSleep ();

Thank you,
Laszlo
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to