> There is most likely a raise to TPL_HIGH and a TPL restore in that path that causes event dispatch.
Is that bad? > Is it one of the edk2 timer libs? If so which one? Nope it's my own, platform specific one(my device hasn't been merged to the official sources yet). Michael On Sat, Nov 14, 2015 at 6:11 PM, Andrew Fish <[email protected]> wrote: > > > On Nov 13, 2015, at 10:53 PM, Michael Zimmermann < > [email protected]> wrote: > > > > > > I think I've made some progress. > > Thx to the fact that the only thing stuck is the ARM thread mode and the > > timer interrupts are still fired(I verified that my callback is called > from > > an interrupt, being it a fluke or not) I could easily dump the current PC > > of the DxeCore context. > > > > There is most likely a raise to TPL_HIGH and a TPL restore in that path > that causes event dispatch. > > > This way I discovered that the code is stuck in the delay functions of > the > > timerLib because they're not thread safe. > > > > Is it one of the edk2 timer libs? If so which one? > > Thanks, > > Andrew Fish > > > The reason is that a hw counter gets reset and started for this and if > this > > happens from an interrupt(UART uses delay functions) while the thread > mode > > is whiting for the counter to reach an specific value it will just wait > > forever because the counter gets disabled after the delay. > > > > Code: > > usecs = (usecs * 33 + 1000 - 33) / 1000; > > > > writel(0, GPT_CLEAR); > > writel(0, GPT_ENABLE); > > while (readl(GPT_COUNT_VAL) != 0) ; > > > > writel(GPT_ENABLE_EN, GPT_ENABLE); > > while (readl(GPT_COUNT_VAL) < usecs) ; > > > > writel(0, GPT_ENABLE); > > writel(0, GPT_CLEAR); > > > > I guess I need to try keeping the counter running and detect when it > rolled > > over to make it thread-safe. > > > > Michael > > > > On Fri, Nov 13, 2015 at 1:14 AM, Andrew Fish <[email protected]> wrote: > > > >> > >>> On Nov 12, 2015, at 11:21 AM, Michael Zimmermann < > >> [email protected]> wrote: > >>> > >>> thx for this information. > >>> I don't have any debug hw but UART. > >>> > >>> After some careful DEBUG printing and tracing the call stack using > >>> '__builtin_return_address(0)' > >> > >> FYI the edk2 has a portable form of this RETURN_ADDRESS(0) > >> > >>> I found that the application's dead happens > >>> at 'WaitForEvent' > >> > >> The WaitForEvent() is what happens at the shell prompt when it is > waiting > >> for keyboard input. So that is functioning as intended. > gBS->WaitForEvent() > >> is the power efficient way to wait. > >> > >> If you look at CoreWaitForEvent() it checks all the events, and then > calls > >> CoreSignalEvent with the gIdleLoopEvent. If the DXE Cpu driver supports > >> this feature gIdleLoopEvent will put the CPU in a low power state until > the > >> next timer tick. Since CoreWaitForEvent() checked all the event state > it > >> can not change until the next timer tick so this lets the system spend > its > >> idle time in a lower power mode. > >> > >> > >> > https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/Event/Event.c#L685 > >> for(;;) { > >> > >> for(Index = 0; Index < NumberOfEvents; Index++) { > >> > >> Status = CoreCheckEvent (UserEvents[Index]); > >> > >> // > >> // provide index of event that caused problem > >> // > >> if (Status != EFI_NOT_READY) { > >> if (UserIndex != NULL) { > >> *UserIndex = Index; > >> } > >> return Status; > >> } > >> } > >> > >> // > >> // Signal the Idle event > >> // > >> CoreSignalEvent (gIdleLoopEvent); > >> } > >> > >> So if you are really stuck here it could imply your Simple Text In is > >> hung? Maybe your issue is data corruption vs an event issue? > >> > >>> and that there aren't any long running events(it returns > >>> from CoreDispatchEventNotifies and CoreRestoreTpl everytime). > >>> > >>> I'm not sure this is always the case though because without the DEBUG's > >> the > >>> application can even stop when the edk2 shell is printing the device > map > >>> and WaitForEvent usually is only used for key input. > >>> > >>> isn't there some GCC option to save the stacktrace so I can dump it > after > >>> some seconds runtime(when the system died) and just print the whole > >>> backtrace?(like the linux kernel does). > >>> > >> > >> Well this is when it gets tricky. For VC++ you can only > _ReturnAddress(), > >> and that is equivalent of __builtin_return_address(0) on the GCC side. > But > >> it gets worse... To get a stack trace for X64 with VC++ you need > symbols as > >> the unwind is in the .PDB file. > >> > >> For clang, and I think with the right GCC compiler flags, you can walk > the > >> stack as each routine saves the frame pointer on entry. This is a simple > >> X64 C function that just returns 0. The push of the %rbp and saving %rsp > >> allow the stack to be unwound in software. > >> > >> pushq %rbp > >> movq %rsp, %rbp > >> xorl %eax, %eax > >> popq %rbp > >> retq > >> > >> So it is possible to unwind the stack in software. > >> > >> Simple answer is try RETURN_ADDRESS(1), RETURN_ADDRESS(2), etc. If it is > >> supported the compiler will generate the code to unwind for you. > >> > >> Complex answer is write the stack unwind code, if it is possible? Which > >> Processor and I assume you are using GCC? > >> > >> You can use the GetImageName() function in > >> > https://github.com/tianocore/edk2/blob/master/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerUefi.c#L64 > >> to see how you can use the PE/COFF library functions to convert a > >> FaultAddress to the ImageBase, and name of the image. If you know the > >> offset into the image relative to the start you can load image in gdb > from > >> the build output directory and see what code it maps to. > >> > >> The X86 version of all this lives: > >> > https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c > >> > >> Thanks, > >> > >> Andrew Fish > >> > >>> On Thu, Nov 12, 2015 at 7:39 PM, Andrew Fish <[email protected]> wrote: > >>> > >>>> > >>>> On Nov 12, 2015, at 9:05 AM, Michael Zimmermann < > >> [email protected]> > >>>> wrote: > >>>> > >>>> thx, this perfectly explains my situation(that EDK2 shell stops while > >>>> printing sth. like the map or waiting for this 5s startup.nsh > timeout). > >>>> > >>>> So this means that processing the event queue is caused by any API > call > >>>> which never returns to the DXE phase for some reason. > >>>> > >>>> > >>>> You should also check your code looking for TPL violations. Calling > EFI > >>>> Services at to high a TPL can lead to undefined behavior. > >>>> > >>>> If you look at the UEFI 2.5 spec, Section 6.1 Event, Timer, and Task > >>>> Priority Services Table 23 lists TPL Restrictions. You can check that > >> your > >>>> code is not violating any of these restrictions. The natural reaction > >> for > >>>> some one having performance issues is to cheat and try to elevate > their > >>>> TPL. > >>>> > >>>> > >>>> ... > >>>> > >>>> The class of bugs created by calling EFI Services at to hight a TPL > are > >>>> usually reentrancy related. Basically the locks in the DXE Core raise > >> TPL > >>>> to protect critical sections, like the protocol data base or event > >> queue. > >>>> Calling at an illegal TPL can cause corruption of some of these > >> structures, > >>>> and thus undefined behavior. > >>>> > >>>> Another possibility is an event TPL deadlock. When your event runs at > a > >>>> TPL only events of a higher TPL can run. Your event is blocking code > at > >> <= > >>>> current TPL from running. So if your event is waiting on something to > >>>> complete that needs to run at <= the current TPL that code is starved > >> and > >>>> will never get run. The TPL Restriction table is the guide here also. > >> For > >>>> example if you driver implements Block IO it can be called at TPL <= > >>>> TPL_CALLBACK, so if your driver has an event that needs to complete to > >> make > >>>> forward progress it needs to run at TPL_NOTIFY. > >>>> > >>>> Since you are producing GOP, there is going to be system code that > >>>> implements Simple Text Output on top of GOP so you inherit those TPL > >>>> restrictions. > >>>> > >>>> Is there a special way to debug the event system or do I have to put > >> DEBUG > >>>> calls all over the place? > >>>> > >>>> > >>>> Actually putting DEBUG prints all over the place can make it worse as > >> you > >>>> can increase the amount of time spent processing events. > >>>> > >>>> I'm not sure if you have a debugger, but if you do.... > >>>> 1) I'd break in a few times during the hang to try and get an idea of > >>>> which event is taking all the time from the back trace > >>>> 2) Pay attention to the TPL when you break in, dump gEfiCurrentTpl > >>>> 3) You can walk the gEventQueue[] LIST_ENTRY to see what events are > >>>> active. >= your current TPL. > >>>> 4) As I mentioned I have lldb scripts to dump queues so you can figure > >> out > >>>> the high frequency timer functions and inspect that code. > >>>> > >>>> If you don't have a debugger... > >>>> 1) Add DEBUG print to CoreCreateEventInternal() and print out info > about > >>>> timer events that get created. Then you can look at the timer event > >>>> functions. > >>>> 2) CoreDispatchEventNotifies() calls the event notify functions. > >>>> Event->NotifyFunction (Event, Event->NotifyContext); > >>>> You can use the TimerLib to try and figure out what event is taking al > >> the > >>>> time. You can DEBUG print the slowest function, and maybe only do it > >> every > >>>> Nth time so you don't do it 1,000 times a second. > >>>> You could also add code to figure out if the function is running > longer > >>>> than (or some large percentage of) its period. > >>>> > >>>> > >>>> Caveat Emptor .... > >>>> Assume it is your event and figure out if you are doing something slow > >> at > >>>> an elevated TPL, calling a service at too hight a TPL., or have TPL > >>>> related deadlock based on the TPL restrictions. > >>>> > >>>> Thanks, > >>>> > >>>> Andrew Fish > >>>> > >>>> PS Sorry if this is more detail than you needed, but I figured other > >> folks > >>>> might find this useful. > >>>> > >>>> > >>>> On Thu, Nov 12, 2015 at 5:44 PM, Andrew Fish <[email protected]> wrote: > >>>> > >>>>> > >>>>>> On Nov 12, 2015, at 3:28 AM, Andrew Fish <[email protected]> wrote: > >>>>>> > >>>>>>> > >>>>>>> On Nov 12, 2015, at 3:22 AM, Andrew Fish <[email protected]> wrote: > >>>>>>> > >>>>>>> > >>>>>>>> On Nov 12, 2015, at 12:49 AM, Michael Zimmermann < > >>>>> [email protected]> wrote: > >>>>>>>> > >>>>>>>> Stall was just an example, I can also use DEBUG. My timer interval > >> is > >>>>>>>> 100ms(I converted it from the 100ns unit). > >>>>>>>> > >>>>>>>> What I meant with "thread mode code" is the "normal" non IRQ > context > >>>>> code > >>>>>>>> running on the CPU. That means that there are actually two > contexts > >> in > >>>>>>>> EDK2, the exception(i.e. IRQ's like the Timer/Watchdog) and the > >>>>> normal mode > >>>>>>>> all code is running in. > >>>>>>>> > >>>>>>> > >>>>>>> OK thanks that helps. The timer ISR runs in interrupt context, and > >>>>> from an ARM point of view EFI is running the ARM "Thread mode". The > >> ISR > >>>>> context is an implementation detail and not really defined by the > >>>>> specification. > >>>>>>> > >>>>>>> I'd also point out the Events dispatch independent of the interrupt > >>>>> context. gBS->RestoreTpl() can cause events to dispatch. For example > a > >> lot > >>>>> of the EFI Protocol services have locks that raise TPL to prevent > >>>>> recursion. When these locks are released and the TPL is restored > >> events are > >>>>> dispatched. So just calling EFI services can cause events to run. So > >>>>> conceptually you can ignore the interrupt context, as that is used to > >>>>> implement the timer tick. Every thing else is an event that runs in > the > >>>>> main EFI context. > >>>>>>> > >>>>>>> > >>>>> > >> > https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/Event/Tpl.c#L126 > >>>>>>> > >>>>>> > >>>>>> As Kinney pointed out the events are cooperative and there is no > >>>>> scheduler, so if you are getting stuck some chunk of code is running > >> too > >>>>> long at an elevated TPL. You may need to performance profile to > figure > >> out > >>>>> the bad code. > >>>>>> > >>>>> > >>>>> The events are managed by queues in the DXE Core. The events are > >>>>> described by the IEVENT data structure and linked into queues based > on > >>>>> state. The state transition to the event is calling a C function > >> stored in > >>>>> the IEVENT. The event must return, or call an EFI service, to give > >> control > >>>>> back to the DXE Core. > >>>>> > >>>>> > >>>>> > >> > https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/Event/Event.c > >>>>> > >>>>> /// > >>>>> /// gEventQueueLock - Protects the event queues > >>>>> /// > >>>>> EFI_LOCK gEventQueueLock = EFI_INITIALIZE_LOCK_VARIABLE > >> (TPL_HIGH_LEVEL); > >>>>> > >>>>> /// > >>>>> /// gEventQueue - A list of event's to notify for each priority level > >>>>> /// > >>>>> LIST_ENTRY gEventQueue[TPL_HIGH_LEVEL + 1]; > >>>>> > >>>>> /// > >>>>> /// gEventPending - A bitmask of the EventQueues that are pending > >>>>> /// > >>>>> UINTN gEventPending = 0; > >>>>> > >>>>> /// > >>>>> /// gEventSignalQueue - A list of events to signal based on > EventGroup > >>>>> type > >>>>> /// > >>>>> LIST_ENTRY gEventSignalQueue = INITIALIZE_LIST_HEAD_VARIABLE > >>>>> (gEventSignalQueue); > >>>>> > >>>>> It is possible to write a debugger script to dump out the info about > >> the > >>>>> events if you have source level debug available for the DXE Core. > >>>>> > >>>>> Thanks, > >>>>> > >>>>> Andrew Fish > >>>>> > >>>>>> Thanks, > >>>>>> > >>>>>> Andrew Fish > >>>>>> > >>>>>> > >>>>>>> Thanks, > >>>>>>> > >>>>>>> Andrew Fish > >>>>>>> > >>>>>>> > >>>>>>>> On Thu, Nov 12, 2015 at 9:27 AM, Andrew Fish <[email protected]> > >> wrote: > >>>>>>>> > >>>>>>>>> > >>>>>>>>>> On Nov 11, 2015, at 11:51 PM, Michael Zimmermann < > >>>>>>>>> [email protected]> wrote: > >>>>>>>>>> > >>>>>>>>>> I've started investigating in the timer event problem and I > think > >> I > >>>>> have > >>>>>>>>>> some weird problem with my platform drivers(I hope, so it's not > a > >>>>> EDK2 > >>>>>>>>> bug). > >>>>>>>>>> > >>>>>>>>>> If I create a timer that runs every 100ms which does nothing > but a > >>>>>>>>>> stall(1), the thread mode code stops after some random > >> time(usually > >>>>> in > >>>>>>>>> edk2 > >>>>>>>>>> shell so I guess it's a race condition which needs some cpu > load). > >>>>>>>>>> > >>>>>>>>> > >>>>>>>>> Michael, > >>>>>>>>> > >>>>>>>>> Watch out as Stall() is Microseconds, and SetTimer() is 100ns > I've > >>>>> seen > >>>>>>>>> bugs like that before in code. > >>>>>>>>> > >>>>>>>>>> When threadmode code is stopped the timer continues getting > called > >>>>> and > >>>>>>>>> even > >>>>>>>>>> if I stop the timer afterwards(with CloseEvent) it keeps being > >>>>> stopped. > >>>>>>>>>> > >>>>>>>>>> Is there a way to get the threadmode context from inside a timer > >>>>>>>>> callback? > >>>>>>>>>> This way I could read the PC to check what's going on. > >>>>>>>>>> > >>>>>>>>> > >>>>>>>>> There are no threads. EFI is an event model. If your code is > >> running > >>>>> you > >>>>>>>>> are blocking every one else's forward progress. Only code running > >> at > >>>>> a > >>>>>>>>> higher TPL can preempt. So when your event is running it is > >> blocking > >>>>> the > >>>>>>>>> main flow and any event trying to run at <= TPL of your event > from > >>>>> making > >>>>>>>>> forward progress. gBS->Stall() does not yield, it is no different > >>>>> than > >>>>>>>>> running code. > >>>>>>>>> > >>>>>>>>> So there is only one context, you can print it out any time you > >> want. > >>>>>>>>> > >>>>>>>>> Thanks, > >>>>>>>>> > >>>>>>>>> Andrew Fish > >>>>>>>>> > >>>>>>>>> PS When folks yell at us for not having threads in EFI we point > >> them > >>>>> at: > >>>>>>>>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__web.stanford.edu_-7Eouster_cgi-2Dbin_papers_threads.pdf&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=60wp7PciYqIO8kDWvG2i0EVI8x_Mt0wPgpxjGCfkSEA&e= > >>>>>>>>> > >>>>>>>>> > >>>>>>>>>> Michael > >>>>>>>>>> > >>>>>>>>>> On Wed, Nov 11, 2015 at 8:10 PM, Kinney, Michael D < > >>>>>>>>>> [email protected]> wrote: > >>>>>>>>>> > >>>>>>>>>>> Michael, > >>>>>>>>>>> > >>>>>>>>>>> A periodic event timer at 30 times a second should not cause > >> pauses > >>>>>>>>>>> forever, unless the action you are performing in the event > >>>>> notification > >>>>>>>>>>> function takes more than 1/30 of a second to complete. You > >> should > >>>>> be > >>>>>>>>> able > >>>>>>>>>>> to just add a periodic event handler that does nothing, so you > >> can > >>>>>>>>> measure > >>>>>>>>>>> what the overhead is. > >>>>>>>>>>> > >>>>>>>>>>> Another option is to use the performance counter in the > TimerLib > >>>>> each > >>>>>>>>> time > >>>>>>>>>>> a Blt() is called (GetPerformanceCounterProperties() and > >>>>>>>>>>> GetPerformanceCounter()). When Blt() is called frequently, the > >>>>> amount > >>>>>>>>> of > >>>>>>>>>>> time since last vsync will have elapsed, and you can go the > vsync > >>>>> action > >>>>>>>>>>> within the Blt() call. If you also set a one shot timer event, > >> so > >>>>> if > >>>>>>>>> the > >>>>>>>>>>> last call to Blt() did not do a vsync and there are no more > Blt() > >>>>> calls, > >>>>>>>>>>> 1/30th of a second later, the vsync action can be done. Every > >> time > >>>>>>>>> Blt() > >>>>>>>>>>> is called, the one shot timer can be re-armed. This way, the > one > >>>>> shot > >>>>>>>>>>> timer event is not actually executed very often. > >>>>>>>>>>> > >>>>>>>>>>> Mike > >>>>>>>>>>> > >>>>>>>>>>>> -----Original Message----- > >>>>>>>>>>>> From: edk2-devel [mailto:[email protected]] On > >>>>> Behalf Of > >>>>>>>>>>> Michael Zimmermann > >>>>>>>>>>>> Sent: Wednesday, November 11, 2015 12:32 AM > >>>>>>>>>>>> To: [email protected] > >>>>>>>>>>>> Subject: [edk2] EFI GOP with manual vsync trigger > >>>>>>>>>>>> > >>>>>>>>>>>> Hi, > >>>>>>>>>>>> > >>>>>>>>>>>> my Graphics HW uses a manual vsync trigger. That means that > >> after > >>>>>>>>> drawing > >>>>>>>>>>>> to the framebuffer I need to manually trigger vsync(you can > >>>>> compare it > >>>>>>>>> to > >>>>>>>>>>>> switching between double buffers). > >>>>>>>>>>>> > >>>>>>>>>>>> The problem is that UEFI's GraphicsOutputProtocol(GOP) doesn't > >>>>> take > >>>>>>>>> care > >>>>>>>>>>> of > >>>>>>>>>>>> HW that needs a flush. > >>>>>>>>>>>> While issuing the trigger after every Blt Operation works, > this > >>>>>>>>> obviously > >>>>>>>>>>>> causes extremely slow rendering for applications like the > Shell > >>>>> which > >>>>>>>>> call > >>>>>>>>>>>> Blt very often(like for every character). > >>>>>>>>>>>> > >>>>>>>>>>>> Also I can't use a timer to set the trigger(like 30times a > >> second) > >>>>>>>>> because > >>>>>>>>>>>> it takes too much time and the Timer Interrupt ends up > consuming > >>>>> too > >>>>>>>>> much > >>>>>>>>>>>> time and the "normal" code gets paused forever. > >>>>>>>>>>>> > >>>>>>>>>>>> Do you have any other ideas how to handle this? > >>>>>>>>>>>> > >>>>>>>>>>>> Thx > >>>>>>>>>>>> Michael > >>>>>>>>>>>> _______________________________________________ > >>>>>>>>>>>> edk2-devel mailing list > >>>>>>>>>>>> [email protected] > >>>>>>>>>>>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > >>>>>>>>>>> > >>>>>>>>>> _______________________________________________ > >>>>>>>>>> edk2-devel mailing list > >>>>>>>>>> [email protected] > >>>>>>>>>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > >>>>>>>>> > >>>>>>>>> > >>>>>>>> _______________________________________________ > >>>>>>>> edk2-devel mailing list > >>>>>>>> [email protected] > >>>>>>>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > >>>>>>> > >>>>>>> _______________________________________________ > >>>>>>> edk2-devel mailing list > >>>>>>> [email protected] > >>>>>>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > >>>>> > >>>>> > >>>> > >>>> > >>>> > >>> _______________________________________________ > >>> edk2-devel mailing list > >>> [email protected] > >>> > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > >> > >> > > _______________________________________________ > > edk2-devel mailing list > > [email protected] > > > https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=Hw-EJUFt2_D9PK5csBJ29kRV40HqSDXWTLPyZ6W8u84&r=4sdzHKz0eU1vXqaUySVmyA&m=iyUc8eXmiD7L89LghmMd5hdgVupHEDfyZBXpjyiE-9I&s=31tD1YVkelbWB8njOCusaOe0MPbnDWaBzkwrYlfpysw&e= > > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

