* purpose of EFI_LOCK
@ 2023-05-04 8:45 Laszlo Ersek
2023-05-04 18:01 ` Andrew Fish
0 siblings, 1 reply; 5+ messages in thread
From: Laszlo Ersek @ 2023-05-04 8:45 UTC (permalink / raw)
To: edk2-devel-groups-io
Cc: Michael Kinney, Andrew Fish, Michael Brown, Gerd Hoffmann
Hi,
what benefit does EFI_LOCK add, over direct gBS->RaiseTPL() and
gBS->RestoreTPL() calls?
Considering just the two APIs EfiAcquireLock() and EfiReleaseLock():
- The "Lock" field (effectively, lock status field) is useless; it is
only written to, never read (outside of ASSERT()s)
- The "OwnerTpl" and "Tpl" fields are just convenience storage for the
new TPL we raise to, and the old TPL we restore.
Considering the EfiAcquireLockOrFail() API as well:
- This does read the "Lock" (lock status) field, and if it is
EfiLockAcquired, the RaiseTPL() call is refused. So the idea here seems
to be to ensure a *strict* rise in the TPL. Namely, the RaiseTPL() in
EfiAcquireLockOrFail() would still succeed after the RaiseTPL() in
EfiAcquireLock() -- it is valid to "raise" the TPL to the current TPL
--, but the lock status check prevents that.
- However (#1), this same "strict" raise would be possible by just
calling RaiseTPL() again, and comparing the returned old TPL against the
TPL we've just set as new. If the old TPL is strictly lower, then we've
just "acquired the lock", otherwise we've "already been holding" the
lock. So, from this perspective, EfiAcquireLockOrFail() doesn't add much.
- Furthermore (#2), if another agent raised the TPL already, but didn't
use our particlar EFI_LOCK object to do that, then the status stored in
"EFI_LOCK.Lock" will not be able to track anything.
So what is EFI_LOCK good for?
Effectively I'm disturbed by the *name* "EFI_LOCK". A lock (or mutex) is
supposed to protect some shared resource. If two agents access the
resource without first acquiring the lock, there's trouble. Therefore
the resource itself becomes qualified as "requiring protection by the
lock, at all times". However, the "current TPL" is *not* a resource like
that. It's a UEFI spec level concept; the RaiseTPL and RestoreTPL boot
services are available to any agents; those agents are *not* required to
go through any kind of extra mutual exclusion.
I've also considered that maybe EFI_LOCK could provide some protection
against inadvertently *lowering* the TPL via RaiseTPL() (which is
undefined behavior, per spec). But I don't see how --
EfiAcquireLockOrFail() will happily lower the TPL if the Lock field is
EfiLockReleased, but another agent has meanwhile raised the TPL strictly
above the Tpl field.
Please explain. :)
Thanks!
Laszlo
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: purpose of EFI_LOCK
2023-05-04 8:45 purpose of EFI_LOCK Laszlo Ersek
@ 2023-05-04 18:01 ` Andrew Fish
2023-05-05 19:59 ` Laszlo Ersek
0 siblings, 1 reply; 5+ messages in thread
From: Andrew Fish @ 2023-05-04 18:01 UTC (permalink / raw)
To: Laszlo Ersek
Cc: edk2-devel-groups-io, Mike Kinney, Michael Brown, Gerd Hoffmann
[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]
Laszlo,
Hope you are doing well! Sorry to top post but I’m just commenting on the big picture, not answering your specific questions yet.
The Wiki definition of lock is something like: In computer science locks are a mechanism that enforces limits on access to a resource when there is the possibility for contention between threads of execution. I think the key point here is “threads of execution” is not threads….
UEFI is single threaded with a cooperative event model. There is no scheduler and an event blocks all forward progress of any event at the same or lower TPL. The protocol services have defined TPL Restrictions [1] so that is possible to implement locking. In the context of EFI raising the TPL blocks any “threads of execution” (events) that could preempt the running code from contending with a critical section.
Lets thing about what would happen if you use an atomic primitive as a lock in EFI. Let’s say the app is installing a protocol so the DXE Core has the protocol database locked. Any event that fired in that window would not be able to call any UEFI Boot Service that was related to protocols and expect it to succeed. If the event blocked on the lock, the system is dead locked. If the the lock was tested and failed that basically means it would be normal for any UEFI service to fail in events and event code needed to coded to deal with that. Basically the even could we need to defer to a future time the event gets signaled. I think think this quickly devolves in the event code having to implement a simple scheduler for its set. Thus making locks raise the TPL is just better for everyone.
Not that we have always been good at naming things, but in the context of EFI a Lock is best implemented as raising TPL so we made an up level look API to make that clear to people, and to help educate people how locks should be implemented in EFI.
This is old, but it is a good sumarry of why we did not want BIOS programmers dealing with threads 20+ years ago when we designed EFI.
https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf
threads
PDF Document · 107 KB
[1]
https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions
Thanks,
Andrew Fish
> On May 4, 2023, at 1:45 AM, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Hi,
>
> what benefit does EFI_LOCK add, over direct gBS->RaiseTPL() and
> gBS->RestoreTPL() calls?
>
> Considering just the two APIs EfiAcquireLock() and EfiReleaseLock():
>
> - The "Lock" field (effectively, lock status field) is useless; it is
> only written to, never read (outside of ASSERT()s)
>
> - The "OwnerTpl" and "Tpl" fields are just convenience storage for the
> new TPL we raise to, and the old TPL we restore.
>
> Considering the EfiAcquireLockOrFail() API as well:
>
> - This does read the "Lock" (lock status) field, and if it is
> EfiLockAcquired, the RaiseTPL() call is refused. So the idea here seems
> to be to ensure a *strict* rise in the TPL. Namely, the RaiseTPL() in
> EfiAcquireLockOrFail() would still succeed after the RaiseTPL() in
> EfiAcquireLock() -- it is valid to "raise" the TPL to the current TPL
> --, but the lock status check prevents that.
>
> - However (#1), this same "strict" raise would be possible by just
> calling RaiseTPL() again, and comparing the returned old TPL against the
> TPL we've just set as new. If the old TPL is strictly lower, then we've
> just "acquired the lock", otherwise we've "already been holding" the
> lock. So, from this perspective, EfiAcquireLockOrFail() doesn't add much.
>
> - Furthermore (#2), if another agent raised the TPL already, but didn't
> use our particlar EFI_LOCK object to do that, then the status stored in
> "EFI_LOCK.Lock" will not be able to track anything.
>
> So what is EFI_LOCK good for?
>
> Effectively I'm disturbed by the *name* "EFI_LOCK". A lock (or mutex) is
> supposed to protect some shared resource. If two agents access the
> resource without first acquiring the lock, there's trouble. Therefore
> the resource itself becomes qualified as "requiring protection by the
> lock, at all times". However, the "current TPL" is *not* a resource like
> that. It's a UEFI spec level concept; the RaiseTPL and RestoreTPL boot
> services are available to any agents; those agents are *not* required to
> go through any kind of extra mutual exclusion.
>
> I've also considered that maybe EFI_LOCK could provide some protection
> against inadvertently *lowering* the TPL via RaiseTPL() (which is
> undefined behavior, per spec). But I don't see how --
> EfiAcquireLockOrFail() will happily lower the TPL if the Lock field is
> EfiLockReleased, but another agent has meanwhile raised the TPL strictly
> above the Tpl field.
>
> Please explain. :)
>
> Thanks!
> Laszlo
>
[-- Attachment #2.1: Type: text/html, Size: 7983 bytes --]
[-- Attachment #2.2: preview.png --]
[-- Type: image/png, Size: 112469 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: purpose of EFI_LOCK
2023-05-04 18:01 ` Andrew Fish
@ 2023-05-05 19:59 ` Laszlo Ersek
2023-05-05 22:25 ` [edk2-devel] " vincent zimmer
0 siblings, 1 reply; 5+ messages in thread
From: Laszlo Ersek @ 2023-05-05 19:59 UTC (permalink / raw)
To: Andrew (EFI) Fish
Cc: edk2-devel-groups-io, Mike Kinney, Michael Brown, Gerd Hoffmann
Hi Andrew,
thank you! The background / paragraph on the naming helps!
Cheers,
Laszlo
On 5/4/23 20:01, Andrew (EFI) Fish wrote:
> Laszlo,
>
> Hope you are doing well! Sorry to top post but I’m just commenting on
> the big picture, not answering your specific questions yet.
>
> The Wiki definition of lock is something like: In computer science
> locks are a mechanism that enforces limits on access to a resource when
> there is the possibility for contention between threads of execution. I
> think the key point here is “threads of execution” is not threads….
>
> UEFI is single threaded with a cooperative event model. There is no
> scheduler and an event blocks all forward progress of any event at the
> same or lower TPL. The protocol services have defined TPL Restrictions
> [1] so that is possible to implement locking. In the context of EFI
> raising the TPL blocks any “threads of execution” (events) that could
> preempt the running code from contending with a critical section.
>
> Lets thing about what would happen if you use an atomic primitive as a
> lock in EFI. Let’s say the app is installing a protocol so the DXE Core
> has the protocol database locked. Any event that fired in that window
> would not be able to call any UEFI Boot Service that was related to
> protocols and expect it to succeed. If the event blocked on the lock,
> the system is dead locked. If the the lock was tested and failed that
> basically means it would be normal for any UEFI service to fail in
> events and event code needed to coded to deal with that. Basically the
> even could we need to defer to a future time the event gets signaled. I
> think think this quickly devolves in the event code having to implement
> a simple scheduler for its set. Thus making locks raise the TPL is just
> better for everyone.
>
> Not that we have always been good at naming things, but in the context
> of EFI a Lock is best implemented as raising TPL so we made an up level
> look API to make that clear to people, and to help educate people how
> locks should be implemented in EFI.
>
> This is old, but it is a good sumarry of why we did not want BIOS
> programmers dealing with threads 20+ years ago when we designed EFI.
>
>
> preview.png
> threads <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
> PDF Document · 107 KB
> <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
>
> <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
>
>
> [1]
> https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions <https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions>
>
> Thanks,
>
> Andrew Fish
>
>> On May 4, 2023, at 1:45 AM, Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> Hi,
>>
>> what benefit does EFI_LOCK add, over direct gBS->RaiseTPL() and
>> gBS->RestoreTPL() calls?
>>
>> Considering just the two APIs EfiAcquireLock() and EfiReleaseLock():
>>
>> - The "Lock" field (effectively, lock status field) is useless; it is
>> only written to, never read (outside of ASSERT()s)
>>
>> - The "OwnerTpl" and "Tpl" fields are just convenience storage for the
>> new TPL we raise to, and the old TPL we restore.
>>
>> Considering the EfiAcquireLockOrFail() API as well:
>>
>> - This does read the "Lock" (lock status) field, and if it is
>> EfiLockAcquired, the RaiseTPL() call is refused. So the idea here seems
>> to be to ensure a *strict* rise in the TPL. Namely, the RaiseTPL() in
>> EfiAcquireLockOrFail() would still succeed after the RaiseTPL() in
>> EfiAcquireLock() -- it is valid to "raise" the TPL to the current TPL
>> --, but the lock status check prevents that.
>>
>> - However (#1), this same "strict" raise would be possible by just
>> calling RaiseTPL() again, and comparing the returned old TPL against the
>> TPL we've just set as new. If the old TPL is strictly lower, then we've
>> just "acquired the lock", otherwise we've "already been holding" the
>> lock. So, from this perspective, EfiAcquireLockOrFail() doesn't add much.
>>
>> - Furthermore (#2), if another agent raised the TPL already, but didn't
>> use our particlar EFI_LOCK object to do that, then the status stored in
>> "EFI_LOCK.Lock" will not be able to track anything.
>>
>> So what is EFI_LOCK good for?
>>
>> Effectively I'm disturbed by the *name* "EFI_LOCK". A lock (or mutex) is
>> supposed to protect some shared resource. If two agents access the
>> resource without first acquiring the lock, there's trouble. Therefore
>> the resource itself becomes qualified as "requiring protection by the
>> lock, at all times". However, the "current TPL" is *not* a resource like
>> that. It's a UEFI spec level concept; the RaiseTPL and RestoreTPL boot
>> services are available to any agents; those agents are *not* required to
>> go through any kind of extra mutual exclusion.
>>
>> I've also considered that maybe EFI_LOCK could provide some protection
>> against inadvertently *lowering* the TPL via RaiseTPL() (which is
>> undefined behavior, per spec). But I don't see how --
>> EfiAcquireLockOrFail() will happily lower the TPL if the Lock field is
>> EfiLockReleased, but another agent has meanwhile raised the TPL strictly
>> above the Tpl field.
>>
>> Please explain. :)
>>
>> Thanks!
>> Laszlo
>>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [edk2-devel] purpose of EFI_LOCK
2023-05-05 19:59 ` Laszlo Ersek
@ 2023-05-05 22:25 ` vincent zimmer
2023-05-08 7:36 ` Laszlo Ersek
0 siblings, 1 reply; 5+ messages in thread
From: vincent zimmer @ 2023-05-05 22:25 UTC (permalink / raw)
To: devel, lersek
Cc: Andrew (EFI) Fish, Mike Kinney, Michael Brown, Gerd Hoffmann
Random and tl;dr fun friday fact.
You can see the efi locks replaced w/ spinlocks in
https://github.com/tianocore/edk2-staging/tree/MpNetworkStack to
support the use case described in
https://uefi.org/sites/default/files/resources/7_Maciej%20Vincent_INTEL_network%20stack%20performance.pdf.
These changes along w/ a bespoke threading protocol allow for running
efi networking code across all cores and still be able to interact w/
an enlightened dxe core. We didn't push forward to standardize for
various reasons, such as folks pursuing an alternate solution to the
original problem statement (e.g., LinuxBoot for datacenter network
provisioning) and the huge legacy app compat we'd face. So it's
'possible', just as you 'could' have i/o device interrupt service
routines (isr) w/ their own 'device' tpl's between notify and high
(see "firmware interrupts"
https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-usage)
if you were to expose the appropriate registration and dispatch
interface from the core. I don't think we put anything in staging or
elsewhere public w/ isr examples, though, and I expect trying to
retrofit after 2+ decades would face similar app compat issues w/
folks who already curate their own proprietary device interrupt sol'n.
Vincent
On Fri, May 5, 2023 at 12:59 PM Laszlo Ersek <lersek@redhat.com> wrote:
>
> Hi Andrew,
>
> thank you! The background / paragraph on the naming helps!
>
> Cheers,
> Laszlo
>
> On 5/4/23 20:01, Andrew (EFI) Fish wrote:
> > Laszlo,
> >
> > Hope you are doing well! Sorry to top post but I’m just commenting on
> > the big picture, not answering your specific questions yet.
> >
> > The Wiki definition of lock is something like: In computer science
> > locks are a mechanism that enforces limits on access to a resource when
> > there is the possibility for contention between threads of execution. I
> > think the key point here is “threads of execution” is not threads….
> >
> > UEFI is single threaded with a cooperative event model. There is no
> > scheduler and an event blocks all forward progress of any event at the
> > same or lower TPL. The protocol services have defined TPL Restrictions
> > [1] so that is possible to implement locking. In the context of EFI
> > raising the TPL blocks any “threads of execution” (events) that could
> > preempt the running code from contending with a critical section.
> >
> > Lets thing about what would happen if you use an atomic primitive as a
> > lock in EFI. Let’s say the app is installing a protocol so the DXE Core
> > has the protocol database locked. Any event that fired in that window
> > would not be able to call any UEFI Boot Service that was related to
> > protocols and expect it to succeed. If the event blocked on the lock,
> > the system is dead locked. If the the lock was tested and failed that
> > basically means it would be normal for any UEFI service to fail in
> > events and event code needed to coded to deal with that. Basically the
> > even could we need to defer to a future time the event gets signaled. I
> > think think this quickly devolves in the event code having to implement
> > a simple scheduler for its set. Thus making locks raise the TPL is just
> > better for everyone.
> >
> > Not that we have always been good at naming things, but in the context
> > of EFI a Lock is best implemented as raising TPL so we made an up level
> > look API to make that clear to people, and to help educate people how
> > locks should be implemented in EFI.
> >
> > This is old, but it is a good sumarry of why we did not want BIOS
> > programmers dealing with threads 20+ years ago when we designed EFI.
> >
> >
> > preview.png
> > threads <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
> > PDF Document · 107 KB
> > <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
> >
> > <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
> >
> >
> > [1]
> > https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions <https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions>
> >
> > Thanks,
> >
> > Andrew Fish
> >
> >> On May 4, 2023, at 1:45 AM, Laszlo Ersek <lersek@redhat.com> wrote:
> >>
> >> Hi,
> >>
> >> what benefit does EFI_LOCK add, over direct gBS->RaiseTPL() and
> >> gBS->RestoreTPL() calls?
> >>
> >> Considering just the two APIs EfiAcquireLock() and EfiReleaseLock():
> >>
> >> - The "Lock" field (effectively, lock status field) is useless; it is
> >> only written to, never read (outside of ASSERT()s)
> >>
> >> - The "OwnerTpl" and "Tpl" fields are just convenience storage for the
> >> new TPL we raise to, and the old TPL we restore.
> >>
> >> Considering the EfiAcquireLockOrFail() API as well:
> >>
> >> - This does read the "Lock" (lock status) field, and if it is
> >> EfiLockAcquired, the RaiseTPL() call is refused. So the idea here seems
> >> to be to ensure a *strict* rise in the TPL. Namely, the RaiseTPL() in
> >> EfiAcquireLockOrFail() would still succeed after the RaiseTPL() in
> >> EfiAcquireLock() -- it is valid to "raise" the TPL to the current TPL
> >> --, but the lock status check prevents that.
> >>
> >> - However (#1), this same "strict" raise would be possible by just
> >> calling RaiseTPL() again, and comparing the returned old TPL against the
> >> TPL we've just set as new. If the old TPL is strictly lower, then we've
> >> just "acquired the lock", otherwise we've "already been holding" the
> >> lock. So, from this perspective, EfiAcquireLockOrFail() doesn't add much.
> >>
> >> - Furthermore (#2), if another agent raised the TPL already, but didn't
> >> use our particlar EFI_LOCK object to do that, then the status stored in
> >> "EFI_LOCK.Lock" will not be able to track anything.
> >>
> >> So what is EFI_LOCK good for?
> >>
> >> Effectively I'm disturbed by the *name* "EFI_LOCK". A lock (or mutex) is
> >> supposed to protect some shared resource. If two agents access the
> >> resource without first acquiring the lock, there's trouble. Therefore
> >> the resource itself becomes qualified as "requiring protection by the
> >> lock, at all times". However, the "current TPL" is *not* a resource like
> >> that. It's a UEFI spec level concept; the RaiseTPL and RestoreTPL boot
> >> services are available to any agents; those agents are *not* required to
> >> go through any kind of extra mutual exclusion.
> >>
> >> I've also considered that maybe EFI_LOCK could provide some protection
> >> against inadvertently *lowering* the TPL via RaiseTPL() (which is
> >> undefined behavior, per spec). But I don't see how --
> >> EfiAcquireLockOrFail() will happily lower the TPL if the Lock field is
> >> EfiLockReleased, but another agent has meanwhile raised the TPL strictly
> >> above the Tpl field.
> >>
> >> Please explain. :)
> >>
> >> Thanks!
> >> Laszlo
> >>
> >
>
>
>
>
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [edk2-devel] purpose of EFI_LOCK
2023-05-05 22:25 ` [edk2-devel] " vincent zimmer
@ 2023-05-08 7:36 ` Laszlo Ersek
0 siblings, 0 replies; 5+ messages in thread
From: Laszlo Ersek @ 2023-05-08 7:36 UTC (permalink / raw)
To: Vincent Zimmer, devel
Cc: Andrew (EFI) Fish, Mike Kinney, Michael Brown, Gerd Hoffmann
Thank you Vincent -- I didn't know anything about the MP approach to
edk2 networking, but even more interestingly, I never thought there had
been (successful) attempts to sneak interrupt driven device drivers
(back) into UEFI / edk2. I've always thought (somewhat vaguely perhaps)
that the timer tick was a "set in stone" limit for receiving data.
Laszlo
On 5/6/23 00:25, Vincent Zimmer wrote:
> Random and tl;dr fun friday fact.
> You can see the efi locks replaced w/ spinlocks in
> https://github.com/tianocore/edk2-staging/tree/MpNetworkStack to
> support the use case described in
> https://uefi.org/sites/default/files/resources/7_Maciej%20Vincent_INTEL_network%20stack%20performance.pdf.
> These changes along w/ a bespoke threading protocol allow for running
> efi networking code across all cores and still be able to interact w/
> an enlightened dxe core. We didn't push forward to standardize for
> various reasons, such as folks pursuing an alternate solution to the
> original problem statement (e.g., LinuxBoot for datacenter network
> provisioning) and the huge legacy app compat we'd face. So it's
> 'possible', just as you 'could' have i/o device interrupt service
> routines (isr) w/ their own 'device' tpl's between notify and high
> (see "firmware interrupts"
> https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-usage)
> if you were to expose the appropriate registration and dispatch
> interface from the core. I don't think we put anything in staging or
> elsewhere public w/ isr examples, though, and I expect trying to
> retrofit after 2+ decades would face similar app compat issues w/
> folks who already curate their own proprietary device interrupt sol'n.
> Vincent
>
> On Fri, May 5, 2023 at 12:59 PM Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> Hi Andrew,
>>
>> thank you! The background / paragraph on the naming helps!
>>
>> Cheers,
>> Laszlo
>>
>> On 5/4/23 20:01, Andrew (EFI) Fish wrote:
>>> Laszlo,
>>>
>>> Hope you are doing well! Sorry to top post but I’m just commenting on
>>> the big picture, not answering your specific questions yet.
>>>
>>> The Wiki definition of lock is something like: In computer science
>>> locks are a mechanism that enforces limits on access to a resource when
>>> there is the possibility for contention between threads of execution. I
>>> think the key point here is “threads of execution” is not threads….
>>>
>>> UEFI is single threaded with a cooperative event model. There is no
>>> scheduler and an event blocks all forward progress of any event at the
>>> same or lower TPL. The protocol services have defined TPL Restrictions
>>> [1] so that is possible to implement locking. In the context of EFI
>>> raising the TPL blocks any “threads of execution” (events) that could
>>> preempt the running code from contending with a critical section.
>>>
>>> Lets thing about what would happen if you use an atomic primitive as a
>>> lock in EFI. Let’s say the app is installing a protocol so the DXE Core
>>> has the protocol database locked. Any event that fired in that window
>>> would not be able to call any UEFI Boot Service that was related to
>>> protocols and expect it to succeed. If the event blocked on the lock,
>>> the system is dead locked. If the the lock was tested and failed that
>>> basically means it would be normal for any UEFI service to fail in
>>> events and event code needed to coded to deal with that. Basically the
>>> even could we need to defer to a future time the event gets signaled. I
>>> think think this quickly devolves in the event code having to implement
>>> a simple scheduler for its set. Thus making locks raise the TPL is just
>>> better for everyone.
>>>
>>> Not that we have always been good at naming things, but in the context
>>> of EFI a Lock is best implemented as raising TPL so we made an up level
>>> look API to make that clear to people, and to help educate people how
>>> locks should be implemented in EFI.
>>>
>>> This is old, but it is a good sumarry of why we did not want BIOS
>>> programmers dealing with threads 20+ years ago when we designed EFI.
>>>
>>>
>>> preview.png
>>> threads <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
>>> PDF Document · 107 KB
>>> <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
>>>
>>> <https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf>
>>>
>>>
>>> [1]
>>> https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions <https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.html#tpl-restrictions>
>>>
>>> Thanks,
>>>
>>> Andrew Fish
>>>
>>>> On May 4, 2023, at 1:45 AM, Laszlo Ersek <lersek@redhat.com> wrote:
>>>>
>>>> Hi,
>>>>
>>>> what benefit does EFI_LOCK add, over direct gBS->RaiseTPL() and
>>>> gBS->RestoreTPL() calls?
>>>>
>>>> Considering just the two APIs EfiAcquireLock() and EfiReleaseLock():
>>>>
>>>> - The "Lock" field (effectively, lock status field) is useless; it is
>>>> only written to, never read (outside of ASSERT()s)
>>>>
>>>> - The "OwnerTpl" and "Tpl" fields are just convenience storage for the
>>>> new TPL we raise to, and the old TPL we restore.
>>>>
>>>> Considering the EfiAcquireLockOrFail() API as well:
>>>>
>>>> - This does read the "Lock" (lock status) field, and if it is
>>>> EfiLockAcquired, the RaiseTPL() call is refused. So the idea here seems
>>>> to be to ensure a *strict* rise in the TPL. Namely, the RaiseTPL() in
>>>> EfiAcquireLockOrFail() would still succeed after the RaiseTPL() in
>>>> EfiAcquireLock() -- it is valid to "raise" the TPL to the current TPL
>>>> --, but the lock status check prevents that.
>>>>
>>>> - However (#1), this same "strict" raise would be possible by just
>>>> calling RaiseTPL() again, and comparing the returned old TPL against the
>>>> TPL we've just set as new. If the old TPL is strictly lower, then we've
>>>> just "acquired the lock", otherwise we've "already been holding" the
>>>> lock. So, from this perspective, EfiAcquireLockOrFail() doesn't add much.
>>>>
>>>> - Furthermore (#2), if another agent raised the TPL already, but didn't
>>>> use our particlar EFI_LOCK object to do that, then the status stored in
>>>> "EFI_LOCK.Lock" will not be able to track anything.
>>>>
>>>> So what is EFI_LOCK good for?
>>>>
>>>> Effectively I'm disturbed by the *name* "EFI_LOCK". A lock (or mutex) is
>>>> supposed to protect some shared resource. If two agents access the
>>>> resource without first acquiring the lock, there's trouble. Therefore
>>>> the resource itself becomes qualified as "requiring protection by the
>>>> lock, at all times". However, the "current TPL" is *not* a resource like
>>>> that. It's a UEFI spec level concept; the RaiseTPL and RestoreTPL boot
>>>> services are available to any agents; those agents are *not* required to
>>>> go through any kind of extra mutual exclusion.
>>>>
>>>> I've also considered that maybe EFI_LOCK could provide some protection
>>>> against inadvertently *lowering* the TPL via RaiseTPL() (which is
>>>> undefined behavior, per spec). But I don't see how --
>>>> EfiAcquireLockOrFail() will happily lower the TPL if the Lock field is
>>>> EfiLockReleased, but another agent has meanwhile raised the TPL strictly
>>>> above the Tpl field.
>>>>
>>>> Please explain. :)
>>>>
>>>> Thanks!
>>>> Laszlo
>>>>
>>>
>>
>>
>>
>>
>>
>>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-05-08 7:36 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-04 8:45 purpose of EFI_LOCK Laszlo Ersek
2023-05-04 18:01 ` Andrew Fish
2023-05-05 19:59 ` Laszlo Ersek
2023-05-05 22:25 ` [edk2-devel] " vincent zimmer
2023-05-08 7:36 ` Laszlo Ersek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox