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 <ler...@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 <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 (#104255): https://edk2.groups.io/g/devel/message/104255 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] -=-=-=-=-=-=-=-=-=-=-=-