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 <ler...@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 >> > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#104159): https://edk2.groups.io/g/devel/message/104159 Mute This Topic: https://groups.io/mt/98680041/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/9847357/21656/1706620634/xyzzy [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-