8/22/2015

EfiPy DevicePath

Sample code name

DevicePath.py

Description

In EfiPy2, it uses DevicePath and DevicePathToText to build DevicePathEfiPy.
For the detail, user can reference the source code in Efi\StdLib\lib\python36.8\EfiPy2\MdePkg\Protocol\DevicePathEfiPy.py

DevicePathEfiPy inherit from DevicePath and replace member function __str__ ()to convert device path protocol to readable string.

And this mechanism makes string format available.
  DevicePath = (EfiPy2.cast (TmpDevPath, EfiPy.POINTER(EFI_DEVICE_PATH_PROTOCOL)))[0]

  print ("%s" % DevicePath)

This is LocateHandle sample from EfiPy.gBS.LocateHandle()

  import EfiPy2 as EfiPy

  Status = EfiPy.gBS.LocateHandle(
             EfiPy.ByProtocol,
             EfiPy.byref(gEfiSimpleFileSystemProtocolGuid),
             None,
             EfiPy.byref(BufferSize),
             HandleArray
             )

Above results are put at array of handle.
It can be used by Python for loop to retrieve each handle.

  for Handle in HandleArray:
  
    TmpDevPath = EfiPy.PVOID ()
  
    Status = EfiPy.gBS.HandleProtocol (
                         Handle,
                         EfiPy.byref (gEfiDevicePathProtocolGuid),
                         EfiPy.byref (TmpDevPath)
                         )
    if EfiPy.EFI_ERROR (Status):
      continue
  
    DevicePath = (EfiPy.cast (TmpDevPath, EfiPy.POINTER(EFI_DEVICE_PATH_PROTOCOL)))[0]
  
    print ("%s" % DevicePath)

Screenshot


8/15/2015

EFI_GUID in EfiPy

Description

In EfiPy2, it uses self-defined ctypes structure, similar to EDK II structure, rather then python uuid library.
This is for easy to transfer EFI program from C code to Python.

for example, in EFI C program, it uses

EFI_GUID guid_sample = \
  { \
      0x8D59D32B, 0xC655, 0x4AE9, \
     {0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43} \
  };

In EfiPy2, it can be codded as

>>> from EfiPy2 import EFI_GUID
>>> TestGuid1 = EFI_GUID (
              0x8D59D32B,
              0xC655,
              0x4AE9,
              (0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43)
              )
>>> TestGuid2 = EFI_GUID (
              0x8D59D32B,
              0xC655,
              0x4AE9,
              (0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x44)
              )

EFI_GUID in EfiPy also provide object comparison and string output function

>>> print ("TestGuid1 == TestGuid2 :", TestGuid1 == TestGuid2)
TestGuid1 == TestGuid2 : False

Above result is false because these two GUID have different byte in their capability.

>>> print ("TestGuid1: %s" % TestGuid1)
8D59D32B-C655-4AE9-9B15-F25904992A43

Screenshot of EfiPy2Guild.py




Protocol - 3

Description

EfiPy2 also supports gBS.InstallMultipleProtocolInterfaces().
By EDK II definition,

typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
  IN OUT EFI_HANDLE           *Handle,
  ...
  );

EfiPy2 follows this rule as possible as it can. 

EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES = CFUNCTYPE (
  EFI_STATUS,
  POINTER(EFI_HANDLE)  # IN OUT *Handle
  )

In run time, EfiPy2 changes ctypes CFUNCTYPE argument by re-arrange arguments members.

EfiPy.gBS.InstallMultipleProtocolInterfaces.argtypes = [
      EfiPy.POINTER(EfiPy.EFI_HANDLE),
      EfiPy.POINTER(EfiPy.EFI_GUID),
      EfiPy.POINTER(EfiPy.PVOID),
      EfiPy.POINTER(EfiPy.PVOID)
      ]

Finally, calling EfiPy.gBS.InstallMultipleProtocolInterfaces() for install protocols in one time.

Status = EfiPy.gBS.InstallMultipleProtocolInterfaces (
               EfiPy.byref (Handle1),
               EfiPy.byref (TestGuid1),
               EfiPy.byref (TestProtocol1),
               None
               )

The same is as EfiPy.gBS.UninstallMultipleProtocolInterfaces()

Screenshot

















Sample code in GitHub is EfiPy2ProtocolSample3.py

Protocol - 2

Description

This introduce how to install protocol, protocol event.

Install protocol,
there must be protocol structure and member function prototype defined.

import EfiPy2 as EfiPy

#
# Protocol Structure
#

class TEST_PROTOCOL (EfiPy.Structure):
  _fields_ = [("P1Func1", PROTOCOL_FUNC1),
              ("P1Val",   EfiPy.UINT32),
              ("P1Func2", PROTOCOL_FUNC2)
             ]

#
# Building protocol object
#

P1 = PROTOCOL_FUNC1 (ProtocolFunc1)
P2 = PROTOCOL_FUNC2 (ProtocolFunc2)
TestProtocol1 = TEST_PROTOCOL (P1, 3, P2)

#
# InstallProtocolInterface
#

Status = EfiPy.gBS.InstallProtocolInterface (
                     EfiPy.byref (Handle1),
                     EfiPy.byref (TestGuid1),
                     EfiPy.EFI_NATIVE_INTERFACE,
                     EfiPy.byref (TestProtocol1)
                     )

Protocol event, as same as EDK II, CreateEvent() and RegisterProtocolNotify() are used.

#
# Protocl event variable
#

def ProtocolRegisterFunc (Event, Context):
  print "    Protocl Register notification call back."

Event = EfiPy.EFI_EVENT ()
tFunc = EfiPy.EFI_EVENT_NOTIFY(ProtocolRegisterFunc)
gContext = EfiPy.UINTN (1024)

Status = EfiPy.gBS.CreateEvent (
                     EfiPy.EVT_NOTIFY_SIGNAL,
                     EfiPy.TPL_NOTIFY,
                     tFunc,
                     EfiPy.PVOID.from_address (EfiPy.addressof(gContext)),
                     EfiPy.byref (Event)
                     )

#
# RegisterProtocolNotify
#

Registration = EfiPy.PVOID()

Status = EfiPy.gBS.RegisterProtocolNotify (
                     EfiPy.byref (TestGuid1),
                     Event,
                     EfiPy.byref(Registration)
                     )

screenshot
















Sample code is EfiPy2ProtocolSample2.py at Github.

8/11/2015

Error Handle

Description

By these 2 reasons,
1. Python output run time error to standard error.
2. Some BIOS standard error is not the same as standard output.

We can use try ... exception for output error to standard output
print traceback.format_exc()

Sample code

#
# EfiPy2Error.py
#

import traceback

import EfiPy2 as EfiPy

from EfiPy2.MdePkg.Protocol.SimpleTextOut import     \
                    gEfiSimpleTextOutProtocolGuid,  \
                    EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL

try:
  Status = EfiPy.gBS.LocateProtocol (
             EfiPy.byref (gEfiSimpleTextOutProtocolGuid),
             None,
             EfiPy.byref (Interface)
             )

except:
  print ("Exception Test")
  print (traceback.format_exc())

Due to variable Interface is not initialed before EfiPy.gBS.LocateProtocol in above code, it is an exception.

screenshot

8/10/2015

Protocol - 1

Description

In UEFI Spec., locate protocl with following declaration.
typedef
EFI_STATUS
(EFIAPI *EFI_LOCATE_PROTOCOL)(
  IN  EFI_GUID  *Protocol,
  IN  VOID      *Registration, OPTIONAL
  OUT VOID      **Interface
  );

In EfiPy, it has this mapping declaration.
EFI_LOCATE_PROTOCOL = CFUNCTYPE (
  EFI_STATUS,
  POINTER(EFI_GUID),  # IN  *Protocol
  PVOID,              # IN  *Registration, OPTIONAL
  POINTER(PVOID)      # OUT **Interface
  )

Above, First argument (EFI_STATUS) is function return type.

By ctypes implementation, C language data structure is strong type.
Define PVOID object before locate protocol and transfer it to wanted protocol data object by ctypes cast() function after locate protocol success.

Sample Code

import EfiPy2 as EfiPy

Interface = EfiPy.PVOID ()
Status = EfiPy.gBS.LocateProtocol (
           EfiPy.byref (gEfiSimpleTextOutProtocolGuid),
           None,
           EfiPy.byref (Interface)
           )

TestConOut = EfiPy.cast (
               Interface,
               EfiPy.POINTER(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)
               )

screenshot
















sample source code can be download from Github EfiPy2ProtocolSample1.py

8/09/2015

Variable Operation

Description

Unicode string in Python is codded as u"string". (This is python2 style)

In Unicode HOWTO in Python document, it has the description about how python3 deal strings...
"Python’s string type uses the Unicode Standard for representing characters, which lets Python programs work with all these different possible characters."

EfiPy provides GUID declare, which is similar to EDKII GUID declaration.
NULL (in C language) is codded as None in Python (also in ctypes/EfiPy).
Address of object in python ctypes, it is noted as byref() function
C compatible string in Python ctypes is used by create_string_buffer.

Sample code - simplest EDK II get variable by EfiPy

import EfiPy as EfiPy2

VariableName  = "EfiPyDemo"
VariableGuid  = EfiPy.EFI_GUID( 0x8BE4DF61, 0x93CA, 0x11d2, \
                  (0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8D))
DataSize      = EfiPy.UINTN (0x00)
DataBuffer    = (EfiPy.CHAR8 * 5) ()
Attributes    = EfiPy.UINT32 ()
Status = EfiPy.gRT.GetVariable(
                     VariableName,
                     EfiPy.byref (VariableGuid),
                     EfiPy.byref (Attributes),
                     EfiPy.byref (DataSize),
                     EfiPy.byref (DataBuffer)
                     )

Screenshot
















Sample code is at Github sample folder.

8/08/2015

ReadKey.py

Description

ReadKey.py has these samples... EDKII event (EFI_EVENT), SimpleTextIn protocol and function return value.

In ReadKey.py file, it waits EfiPy.gST.ConIn[0].WaitForKey event in while loop.
EfiPy.gST.ConIn[0] protocol read user input key while event function return EFI_SUCCESS.

In output message, it output EFI_INPUT_KEY data.

source code - WaitForEvent

  import EfiPy2 as EfiPy

  # while (RETURN_ERROR (Status)) {
  while EfiPy.RETURN_ERROR (Status):


    # Status = gBS->
WaitForEvent (
    #                 1,
    #                 & (EFI_EVENT)(gST->ConIn[0].WaitForKey),
    #                 & EventIndex,
    #                 );
    Status = EfiPy.gBS.WaitForEvent (
            1,
            EfiPy.byref(EfiPy.EFI_EVENT(EfiPy.gST.ConIn[0].WaitForKey)),
            EfiPy.byref(EventIndex)
            )

source code - ReadKeyStroke

  # Status = gST->ConIn[0].ReadKeyStroke (
  #                 gST.ConIn, &InputKey
  #                 );
  Status = EfiPy.gST.ConIn[0].ReadKeyStroke (
             EfiPy.gST.ConIn, EfiPy.byref (InputKey)
             )

source code - EFI_INPUT_KEY

  if InputKey.ScanCode != Si.SCAN_NULL:

    EfiPy.gST.ConOut[0].OutputString (
      EfiPy.gST.ConOut,
      u"Scan code 0x%04X is input\r\n" % InputKey.ScanCode
      )

  else:

    EfiPy.gST.ConOut[0].OutputString (
      EfiPy.gST.ConOut,
      u"Input key \"%c\"\r\n" % InputKey.UnicodeChar
      )

screenshot
Sample code from screenshot is uploaded to Github

2024/07014 update
  1. In this sample code, user just adds this python statement (import EfiPy2 as EfiPy) in the file header, then all other parts needn't be modified and works well. 
  2. One bug is found that this program may lead to exception while it received some special key. This error is skipped in commit abdf7b7

import EfiPy2

Description

EfiPy uses python ctypes, which has been ported to UEFI Python package, can be downloaded from EfiPy2 download site.

EfiPy2 is almost mapped to EDKII MdePkg/Include.

#
# import EfiPy2 package
#
import EfiPy2

or

#
# import EfiPy2 package
#
import EfiPy2 as EfiPy

With above python code, import EfiPy2 or import EfiPy2 as EfiPy and running it in UEFI shell environment, it has following features.

1. Basic data type inherited from ctypes (UINTN, UINT32, ...)
2. EFI_SYSTEM_TABLE, EFI_BOOT_SERVICES and EFI_RUNTIME_SERVICES data structure
3. gRT, gST and gBS objects
4. gImageHandle
5. EFI basic data structure

Most usage is import EfiPy2 as EfiPy in these demos and these scripts can be edit and run immediately in UEFI working environment.
There are many macro #define in EDKII source code, it is transferred to constant value/function in EfiPy2.

Some Examples of EfiPy2 base

source code - Table and Services

#
# UEFI basic tables gST, gRT, gBS
#

gRT = EFI_RUNTIME_SERVICES.from_address (_EfiPy2.EfiPygRtAddr)
gST = EFI_SYSTEM_TABLE.from_address     (_EfiPy2.EfiPygStAddr)
gBS = EFI_BOOT_SERVICES.from_address    (_EfiPy2.EfiPygBsAddr)

source code - Handles

#
# EDK basic image handle
#

gImageHandle = EFI_HANDLE.from_address( _EfiPy2.gImageHandle)
# pImageHandle = EFI_HANDLE.from_address( _EfiPy2.pImageHandle)

source code - basic data structure samples

UINT64  = c_uint64
INT64   = c_int64
UINT32  = c_uint32

source code - EfiPy2 constant value/function

#
# ENCODE_ERROR function
#
def ENCODE_ERROR (StatusCode):

  return StatusCode | MAX_BIT  # MAX_BIT is exported from _EfiPy

#
# Return value
#
RETURN_INVALID_PARAMETER     = ENCODE_ERROR (2)

8/07/2015

EfiPy2 - Hello World

Description

To output string by EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL in EFI_SYSTEM_TABLE,
Import EfiPy2 in python and output string, directly.

source code

#
# HelloEfiPy2.py
#

import EfiPy2 as EfiPy

EfiPy.gST.ConOut[0].OutputString(EfiPy.gST.ConOut, "Hello EfiPy2\r\n")

screenshot






8/06/2015

EfiPy initial

Source Code: https://sourceforge.net/projects/efipy/
Sampe code: https://sourceforge.net/u/efipy/svn/HEAD/tree/




Description


EfiPy is a Python Module on UEFI shell which can access UEFI BIOS kernel interface
- System Table
- Runtime Services
- Boot Services

pAnalyzer package -
Tracing UEFI protocol calling flow
Output protocol flow to screen or file with XML format

CorePy (assembly package) -
Simple Assembly code in Python environment.

EfiPy Shell package-
Simple uefi shell program coded with EfiPy library to prove EfiPy workable

EfiPy leverage these open source packages - ctypes, CorePy.
Contact:
efipy.core@gmail.com

2024/7/14 Update

Next generation EfiPy2 can be found here https://github.com/EfiPy/EfiPy2/tree/main