Tuesday, February 28, 2017

Analyze EFI_DRIVER_BINDING_PROTOCOL

In EfiPy_r0.1.3, new EfiPy module bFinder.py including bFinder and bOutClass is added.
Its purpose is to watch which EFI_DRIVER_BINDING_PROTOCOL.Supported() function in binding driver returns EFI_SUCCESS while application/driver calling gBS.ConnectController().

Disk\EFI\StdLib\lib\python.27\EfiPy\Analyzer\bFinder.py includes bFinder module and
Disk\EFI\Samples\ConnectScan.py is the python sample code for calling gBS.ConnectController(). It is referenced from EDKII ShellPkg\Library\UefiShellDriver1CommandsLib\Connect.c.

bFinder.finding() function in bFinder.py, it create pAnalyzer object and for filtering EFI_DRIVER_BINDING_PROTOCOL.Supported and EFI_DRIVER_BINDING_PROTOCOL.Start.

The filter function _filter_func() is used as

pAnalyzer.install("Supported", None, _filter_func)

That is, _filter_func() will be raised after EFI_DRIVER_BINDING_PROTOCOL.Supported is returned.  And no entry filter for EFI_DRIVER_BINDING_PROTOCOL.Supported() function.
In _filter_func(), output message outputs the result to bOutClass object when EFI_DRIVER_BINDING_PROTOCOL.Supported returns EFI_SUCCESS.
_filter_func() opens gEfiLoadedImageProtocolGuid to find device path of binding driver, which maybe the GUID in BIOS image or maybe the file path name in storage media.

Output Class bOutClass (inherit from dOutClass) override member function append().
bOutClass.Append() keeps dummy due to lots of EFI_DRIVER_BINDING_PROTOCOL are called when gBS.ConnectController()is called, these message can be ignored.
Instead,  bFinder uses ExtraOut() as flat output, because  bFinder needs to know which EFI_DRIVER_BINDING_PROTOCOL.Supported return EFI_SUCCESS, only.

pAnalyzer API

pAnaylyzer is used to trace UEFI PROTOCOL calling sequence without changing any UEFI driver on the fly in shell environment.

It includes two basic class dOutClass and BaseAnalyze. pAnalyzer inherit from BaseAnalyze and dOutClass is used for output message.

pAnalyzer
It includes following steps to catch UEFI PROTOCOL calling sequence.

1. Creating pAnalyzer object
pAnalyzer(dOutClass)

2. Designating protocol structure and enumerate protocol members.
pAnalyzer.Build_Capability (EFI_PROTOCOL)

3. Finding installed protocol in step 2.
pAnalyzer.Detect_Protocol (EfiProtocolGuid, EFI_PROTOCOL)

4. Install filter function.
pAnalyzer.install("EFI_PROTOCOL::Function", PreFunc, PostFunc)
PreFunc and PostFunc are optional. PreFunc comes with caller input parameter while PostFunc comes from protocol native function return status. User can monitor/modify input/output parameter and output return value in these two functions.

5. Designating monitor protocol member into log object.
pAnalyzer.start("EFI_PROTOCOL::FunctionName")

After Step 5, any registered (install() and start()) protocol member function log is output to dOutClass.
In folder EfiPy_r0.1.3(20289)\Disk\EFI\Samples in released tar ball, PaTest.py, PaTest2.py and PaTest3.py includes these samples.

pAnalyzer also provides loading EFI drivers and loading EFI Application from Python program by
pAnalyzer.LoadEfiFiles (DrvList, AppList)
DrvList is EFI driver and AppList is EFI application. That is EFI driver/application can be black box for pAnalyzer.

dOutClass
dOutClass output format is XML file.

To add logged message, it is by dOutClass.append() as default. Filter function can add user specified message by it.

After EfiPy_r0.1.3, it can output with flat string, too.
User create new debug output class inherited from dOutClass. In new class, declare new append() function with dummy body and output message via ExtraOut().