I will the align the ReleaseSemaphore & WaitForSemaphore behavior as blow:

ReleaseSemaphore() prevents increase the semaphore if locked, and it should 
return the locked value (MAX_UINT32);  --> then we can check the return value 
is  MAX_UINT32 or not in SmmCpuSyncCheckInCpu(), and sem itself won't be 
changed.
WaitForSemaphore() prevents decrease the semaphore if locked, and it should 
return the locked value (MAX_UINT32); --> then we can check the return value is 
 MAX_UINT32 or not in SmmCpuSyncCheckOutCpu (), and sem itself won'tbe changed.

Thanks,
Jiaxin 


> -----Original Message-----
> From: Wu, Jiaxin
> Sent: Thursday, December 14, 2023 11:35 PM
> To: devel@edk2.groups.io; ler...@redhat.com
> Cc: Dong, Eric <eric.d...@intel.com>; Ni, Ray <ray...@intel.com>; Zeng, Star
> <star.z...@intel.com>; Gerd Hoffmann <kra...@redhat.com>; Kumar, Rahul R
> <rahul.r.ku...@intel.com>
> Subject: RE: [edk2-devel] [PATCH v3 3/6] UefiCpuPkg: Implements
> SmmCpuSyncLib library instance
> 
> > > The code will be changed to:
> > >
> > >   if ((INT32)InternalWaitForSemaphore (Context->CpuCount) < 0) {
> > >     return RETURN_ABORTED;
> > >   }
> >
> > I find this quite ugly. In the "semaphore post" operation, we already
> > have code that prevents incrementing if the semaphore is "locked". Can
> > we perhaps create a "semaphore pend" operation that does the same?
> >
> > How about this:
> >
> > diff --git a/UefiCpuPkg/Library/SmmCpuSyncLib/SmmCpuSyncLib.c
> > b/UefiCpuPkg/Library/SmmCpuSyncLib/SmmCpuSyncLib.c
> > index 3c2835f8def6..5d7fc58ef23f 100644
> > --- a/UefiCpuPkg/Library/SmmCpuSyncLib/SmmCpuSyncLib.c
> > +++ b/UefiCpuPkg/Library/SmmCpuSyncLib/SmmCpuSyncLib.c
> > @@ -91,35 +91,38 @@ UINT32
> >  InternalWaitForSemaphore (
> >    IN OUT  volatile UINT32  *Sem
> >    )
> >  {
> >    UINT32  Value;
> >
> >    for ( ; ;) {
> >      Value = *Sem;
> > +    if (Value == MAX_UINT32) {
> > +      return Value;
> > +    }
> >      if ((Value != 0) &&
> >          (InterlockedCompareExchange32 (
> >             (UINT32 *)Sem,
> >             Value,
> >             Value - 1
> >             ) == Value))
> >      {
> >        break;
> >      }
> >
> >      CpuPause ();
> >    }
> >
> >    return Value - 1;
> >  }
> >
> > Note, I'm just brainstorming here, I've not thought it through. Just to
> > illustrate the direction I'm thinking of.
> >
> > This change should be mostly OK. InternalWaitForSemaphore() returns the
> > decremented value. So, for InternalWaitForSemaphore() to return
> > MAX_UINT32 *without* this update, the function would have to decrement
> > the semaphore when the semaphore is zero. But in that case, the function
> > *blocks*. Thus, a return value of MAX_UINT32 is not possible without
> > this extension; ergo, if MAX_UINT32 is returned (with this extension),
> 
> Yes, that's for the semaphore sync usage, we have to block the sem if it's 
> zero,
> decrease it when return. That's why I said - it's naturally make sure the Run 
> is
> reset after all ready to exit.  Then it can achieve the below flow:
>     BSP: ReleaseOneAp  -->  AP: WaitForBsp
>     BSP: WaitForAPs    <--  AP: ReleaseBsp
> 
> 
> For locked case, I just copy the existing logic from SMM cpu driver (as I
> document in the commit message: The instance refers the existing SMM CPU
> driver (PiSmmCpuDxeSmm) sync implementation and behavior):
> existing ReleaseSemaphore() prevents increase the semaphore, but it still
> return the original semaphore value +1; --> that's why we have to check the
> return value is  0 or not in SmmCpuSyncCheckInCpu()
> existing WaitForSemaphore() allow decrease the semaphore if locked, and it
> also return the original semaphore value -1;  --> that's why we have to check
> the return value is  < 0 or not in SmmCpuSyncCheckOutCpu()
> 
> so, do you want to align the behavior as below?
> 
> ReleaseSemaphore() prevents increase the semaphore if locked, and it should
> return the locked value (MAX_UINT32);  --> then we can check the return
> value is  MAX_UINT32 or not in SmmCpuSyncCheckInCpu(), and sem itself
> won't be changed.
> WaitForSemaphore() prevents decrease the semaphore if locked, and it should
> return the locked value (MAX_UINT32); --> then we can check the return value
> is  MAX_UINT32 or not in SmmCpuSyncCheckOutCpu (), and sem itself won't
> be changed.
> 
> I think:
> for ReleaseSemaphore, it must meet below 2 cases usage:
> 1. for semaphore sync usage (Run), it doesn't care the lock case, and returned
> value is not cared. Just check the semaphore itself.
> 2. for Rendezvous case (Counter), it not only needs to check locked or not
> from return value, but also require "only increase the semaphore if not
> locked".
> 
> for WaitForSemaphore, it must meet below 2 cases usage:
> 1. for semaphore sync usage (Run), it doesn't care the lock case, and returned
> value is not cared. But for the semaphore itself, it need block at 0, and
> decrease when return.
> 2. for Rendezvous case (Counter), it only needs to check locked or not from
> return value. semaphore itself is not cared.
> 
> So, based on above, I think, yes, we can do the change to align the lock
> behavior:
> 
> /**
>   Performs an atomic compare exchange operation to get semaphore.
>   The compare exchange operation must be performed using MP safe
>   mechanisms.
> 
>   @param[in,out]  Sem    IN:  32-bit unsigned integer
>                          OUT: original integer - 1 if Sem is not locked.
>                          OUT: original integer (MAX_UINT32) if Sem is locked.
> 
>   @retval     Original integer - 1 if Sem is not locked.
>               Original integer (MAX_UINT32) if Sem is locked.
> 
> **/
> STATIC
> UINT32
> InternalWaitForSemaphore (
>   IN OUT  volatile UINT32  *Sem
>   )
> {
>   UINT32  Value;
> 
>   for ( ; ;) {
>     Value = *Sem;
>     if (Value == MAX_UINT32) {
>       return Value;
>     }
> 
>     if ((Value != 0) &&
>         (InterlockedCompareExchange32 (
>            (UINT32 *)Sem,
>            Value,
>            Value - 1
>            ) == Value))
>     {
>       break;
>     }
> 
>     CpuPause ();
>   }
> 
>   return Value - 1;
> }
> 
> /**
>   Performs an atomic compare exchange operation to release semaphore.
>   The compare exchange operation must be performed using MP safe
>   mechanisms.
> 
>   @param[in,out]  Sem    IN:  32-bit unsigned integer
>                          OUT: original integer + 1 if Sem is not locked.
>                          OUT: original integer (MAX_UINT32) if Sem is locked.
> 
>   @retval    Original integer + 1 if Sem is not locked.
>              Original integer (MAX_UINT32) if Sem is locked.
> 
> **/
> STATIC
> UINT32
> InternalReleaseSemaphore (
>   IN OUT  volatile UINT32  *Sem
>   )
> {
>   UINT32  Value;
> 
>   do {
>     Value = *Sem;
>   } while (Value + 1 != 0 &&
>            InterlockedCompareExchange32 (
>              (UINT32 *)Sem,
>              Value,
>              Value + 1
>              ) != Value);
> 
>   if (Value == MAX_UINT32) {
>     return Value;
>   }
> 
>   return Value + 1;
> }
> 
> I haven't see any issue with this change.
> 
> > we know the door was locked earlier (and the semaphore is not changed).
> >
> > At the same time, we might want to update InternalReleaseSemaphore() as
> > well, so that it cannot validly increment the semaphore value to
> MAX_UINT32.
> >
> >
> >
> > >
> > >



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#112585): https://edk2.groups.io/g/devel/message/112585
Mute This Topic: https://groups.io/mt/103010165/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to