Saturday, August 22, 2015

EfiPy DevicePath

Sample code name

DevicePath.py

Description

In EfiPy, it uses DevicePath and DevicePathToText to build DevicePathEfiPy.

DevicePathEfiPy inherit from DevicePath and adds output DevicePath text by __str__().

  DevicePath = (EfiPy.cast (TmpDevPath, EfiPy.POINTER(EFI_DEVICE_PATH_PROTOCOL)))[0]

  print "%s" % DevicePath

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

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

Screenshot


Saturday, August 15, 2015

EFI_GUID in EfiPy

Description

In EfiPy, 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 EfiPy, it can be codded as

>>> from EfiPy import *
>>> 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 "%s" % TestGuid1
8D59D32B-C655-4AE9-9B15-F25904992A43

Screenshot of efi_guid.py



Protocol - 3

Description

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

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

EfiPy 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, EfiPy 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 sourceforge is protocol_3.py

Friday, August 14, 2015

Protocol - 2

Description

This introduce how to install protocol, protocol event.

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

#
# 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 protocol2.py at sourceforge.

Tuesday, August 11, 2015

Error Handle

Description

By these 2 reason,
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

import traceback

import EfiPy

from EfiPy.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, it is exception.

screenshot



Monday, August 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

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 sourceforge protocol_1.py

Sunday, August 9, 2015

Variable Operation

Description

Unicode string in Python is codded as u"string".
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

VariableName  = u"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 Sourceforge sample folder.

Saturday, August 8, 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

  # 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 sourceforge

import EfiPy

Description

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

EfiPy is almost mapped to EDKII MdePkg/Include.

#
# import EfiPy package
#
import EfiPy

With above python code, import EfiPy, and running it in UEFI shell environment, it has following benefit.

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

There are many macro #define in EDKII source code, it is transferred to constant value/function in EfiPy

source code - Table and Services

#
# UEFI basic tables gST, gRT, gBS
#

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

source code - Handles

#
# EDK basic image handle
#

gImageHandle = EFI_HANDLE.from_address( _EfiPy.gImageHandle)
pImageHandle = EFI_HANDLE.from_address( _EfiPy.pImageHandle)

source code - basic data structure samples

UINT64  = c_uint64
INT64   = c_int64
UINT32  = c_uint32

source code - EfiPy 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)

Friday, August 7, 2015

EfiPy - Hello World

Description

To output string by EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL in EFI_SYSTEM_TABLE,
Import EfiPy in python source code and output string, directly.

source code

#
# HelloWorld.py
#

import EfiPy

# gST->ConOut[0].OutputString (gST->ConOut, L"Hello World");
EfiPy.gST.ConOut[0].OutputString(EfiPy.gST.ConOut, u"Hello World\r\n")

screenshot



Thursday, August 6, 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