Thursday, December 28, 2017

New package LoLeOp for EfiPy new release - EfiPy_r0.1.5(24622)

Release Note:
Add LoLeOp for x86 IO port, Memory access, CPUID and MSR operation.
Download site: https://sourceforge.net/projects/efipy/
Sample code at EFI\StdLib\lib\python.27\site-packages\LoLeOp\Samples of download tarball.
Its architecture can be improved.
Following are simple samples. For more detail,  it will published in the next of this blog.

Sample of X86 IO port read/write:

from LoLeOp.Io import Io8

# write value 0x10 to IO port 0x70
Io8[0x70] = 0x10

# read value from IO port 0x71
Io71 = Io8[0x71]

# Write bit 0~3 value of IO port 0x70 as 0x02
Io8[0x70][0:3] = 0x02
# read bit 0~3 value of IO port 0x71
IO71_3 = Io8[0x71][0:3]

Sample of Memory read/write:

from LoLeOp.Mem import Mem8, Mem16, Mem32, Mem64

# Read 1 byte from Address 0x0C000000
memX = Mem8[0x0C000000]

# Read 2 byte from Address 0x0C000000
memX = Mem16[0x0C000000]

# Read bit 5 of Address 0x0C000000 
memX = Mem8[0x0C000000][5]

# Set 1 in bit 2 of Address 0x0C000000
Mem8[0x0C000000][2] |= 0x01

Sample of read CPUID:

from LoLeOp.CpuId import CPUID

# Read CPUID index 0x00 (Input parameter EAX as 0x00)
# Assembly code (Intel syntax)
# mov eax, 0x0
# cpuid

CpuId00 = CPUID (0)

# print cpuid instructoin return value of EAX
print "CpuId00.EAX: %X" % CpuId00.EAX

# print cpuid instructoin return value of bit 0, 1 of EAX
print "CpuId00.EAX[0:1]: %X" % CpuId00.EAX[0:1]



# print cpuid instructoin return value of MaximumLeaf of EAX
print "CpuId00.EAX.MaximumLeaf: %X" % CpuId00.EAX.MaximumLeaf


Sample of read SDBG bit from MSR operaton:

# EFI\StdLib\lib\python.27\site-packages\LoLeOp\Samples\SdbgSample.py

from LoLeOp.CpuId import CPUID

from LoLeOp.Msr import rMsr, EFIPY_MSR_COMMON_Reg
from LoLeOp.BitOp import _MemArray

CellExt = {
  # "CellUnion": EFIPY_MSR_COMMON_Reg,
  "CellDefault": EFIPY_MSR_COMMON_Reg,
  "CellArray": {},
  "CellType":  'Uint64',
  "CellBits":  'Bits'
}

print "Looking for platform IA32_DEBUG_INTERFACE status..."

CpuId01 = CPUID (0x01)
if CpuId01.ECX.SDBG != 1:
  print "This platform does not support IA32_DEBUG_INTERFACE...exit."
  exit (0)

print "This platform supports IA32_DEBUG_INTERFACE"
print "SDBG value:            %X" % CpuId01.ECX[11]

msr = _MemArray("msr",  64, CellClass = rMsr, CellExt = CellExt)

# Read bit 0 of MSR 0xC80
print "Enable (R/W):          %x" % msr[0xC80][0]

# Read bit 30 of MSR 0xC80print "Lock (R/W):            %x" % msr[0xC80][30]# Read bit 31 of MSR 0xC80print "Debug Occurred (R/O):  %x" % msr[0xC80][31]

Monday, July 24, 2017

EfiPy_r0.1.4(24622) release

Release Note
This is personal project (author: https://www.facebook.com/wu.max.39).
EfiPy_r0.1.4(24622) is released today for sync for UDK 2017 rev 24622.

What is the next of EfiPy:

1. Easy memory operation in UEFI shell with Python. (Status: in progress)
Example:
1.1. MSR operation:
print "msr[0x1B][8]:    0x%016X" % msr[0x1B][8]
print "msr[0xFE]:       0x%016X" % msr[0xFE]
print "msr[0xFE][7:0]:  0x%016X" % msr[0xFE][7:0]
print "msr[0xFE][0x08]: 0x%016X" % msr[0xFE][0x08]
print "msr[0xFE][0x0A]: 0x%016X" % msr[0xFE][0x0A]

1.2 Memory operation:
print " Mem8[0x3FF39018]: 0x%02X"  % Mem8[0x3FF39018]
print "Mem16[0x3FF39018]: 0x%04X"  % Mem16[0x3FF39018]
print "Mem32[0x3FF39018]: 0x%08X"  % Mem32[0x3FF39018]
print "Mem64[0x3FF39018]: 0x%016X" % Mem64[0x3FF39018]

1.3 IO port
print "Io8[0x71][0:7] & 0x86:   0x%02X" % (Io8[0x71][0:7] & 0x86)
print "Io8[0x71] & 0x86:        0x%02X" % (Io8[0x71]      & 0x86)
print "Io8[0x71][0:7] | 0x86:   0x%02X" % (Io8[0x71][0:7] | 0x86)
print "Io8[0x71][7:0] | 0x86:   0x%02X" % (Io8[0x71][7:0] | 0x86)

1.4 CPUID
print "CPUID(0x01).Regs.EAX.Uint32: 0x%08X" % CPUID(0x01).Regs.EAX.Uint32
print "CPUID(0x01).EAX (Hex): 0x%08X" %       CPUID(0x01).EAX
print "CPUID(0x01).EAX (Bin): %s" %           bin(CPUID(0x01).EAX)
print "===> EAX.SteppingId: [Bits 3:0] Stepping ID"
print "CPUID(0x01).EAX[3:0]: 0x%08X" %        CPUID(0x01).EAX[3:0]
print "CPUID(0x01).EAX.SteppingId: 0x%03X" % CPUID(0x01).EAX.SteppingId

1.5 others...

2. Py2Efi (Status: in progress)
What is Py2Efi?
Capsule program running in EFI shell which packs python libraries into single .efi file.
This capsuled .efi file is a standalone EFI program which makes itself run in another platform without any other python programs.

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().