10/22/2023

EfiPy2 working environment

Introduction

EfiPy2 is python 3 library, is original designed for UEFI shell application. Static data strcuture in EfiPy2 are also suitable being used in OS environmrnt if user can read low layer data, for example PCIe configuration space and complex registers in CPU.

While import EfiPy2 in OS environment, the global data gBS, gST, gRT and gImage are set as fake value to them. That is only static data structure can be apply to Python application and EFI protocol are disabled.

In Windows/Linux system, user can import EfiPy2 without ModuleNotFoundError exception. Thus user Python application can import data structure in EfiPy2.MdePkg.Indusctry and EfiPy2.MdePkg.Register properly. With suitable modifying corepy package, it can also work on EDK2 and Linux system, too.


The conclusion for current stats...

EfiPy2 is full support in UEFI environment.

In Linux system, Python application can import EfiPy2 and corepy. And application can launch corepy code

    % PYTHONPATH=$EfiPy2Path python3

In Windows system, Python application can import EfiPy2

    X:\>set PYTHONPATH=%EfiPy2Path%

    X:\>python


There are two samples for above condition

1. CpuIdBasic.py

    This application leverage corepy excuting cpuid instruction to fetch CPUID data in both UEFI and Linux system.

2. MsrBasic.py

    It can be launched in both Linux and UEFI

    This applicaiton uses rdmsr/wrmsr instructions from corepy, these instrucitons are ring 0 privilege.
    UEFI is a ring 0 environment, too. MsrBasic.py fully achieve msr read/write purpose.
    In Linux, Python run in ring 3 privilege, only related assmbly code is printed in this design while MsrBasic.py is launched.


10/09/2023

CorePy

CorePy

 It is taken back to EfiPy.

There is little of information about corepy. We still can find the fist paper about corepy in PDF.

High-Performance Code Generation Using CorePy

With some modification,  most instructins list in x86_64_isa.py can be used in Linux and EfiPy2, again, with python 3.X. Modified code is here,

PciScan.py, CpuId.py levelage corepy making EfiPy doing low  level operation easier.

Here is snapshot how CpuId.py using cpuid instruction based on corepy library.


10/08/2023

SMBIOS in EfiPy2

EfiPy2Smbios.py

 It is not a new one. The upgrated code it put here.

This sample dumps all SMBIOS items in system as part of screenshot.









Comment

In following comment, due to &SmbiosPointer is not lvalue. It it hard to assign variable SmbiosPointer's address to be other pointer object's adress in C.

Python Efipy (ctypes) capability makes it.






Todo

Although this sample all SMBIOS items in system, There can be improved

1. Dump array objects in SMBIOS

2. Fit variable SMBIOS version

3. Be a SMBIOS library.

2/05/2019

Get IPv4 information via EFI_IP4_CONFIG2_PROTOCOL

This is an example to dump NIC information via UNDI.

This example code uses EFI_IP4_CONFIG2_PROTOCOL for example, only.
Here is the complete source code.

Samples code dumps these informations:
#
# Pseudo code
#
# IfInfo = Ip4Cfg2.EFI_IP4_CONFIG2_INTERFACE_INFO ()
# EFI_IP4_CONFIG2_PROTOCOL.GetData (
#                            Ip4Cfg2P,
#                            Ip4Cfg2.Ip4Config2DataTypeInterfaceInfo,
#                            e.byref (DataSize),
#                            e.cast (e.byref (IfInfo), e.PVOID)
#                            )
#
# Dumpped information
#
EFI_IP4_CONFIG2_INTERFACE_INFO.Name
EFI_IP4_CONFIG2_INTERFACE_INFO.IfType
EFI_IP4_CONFIG2_INTERFACE_INFO.HwAddressSize
EFI_IP4_CONFIG2_INTERFACE_INFO.HwAddress EFI_IP4_CONFIG2_INTERFACE_INFO.StationAddress
EFI_IP4_CONFIG2_INTERFACE_INFO.SubnetMask
EFI_IP4_CONFIG2_INTERFACE_INFO.RouteTableSize

And DNS informations:
#
# Pseudo code
#
# DnsAddr = (e.EFI_IPv4_ADDRESS * \
#            (DataSize.value / e.sizeof (e.EFI_IPv4_ADDRESS))) ()
# Status = Ip4Cfg2P[0].GetData (
#                        Ip4Cfg2P,
#                        Ip4Cfg2.Ip4Config2DataTypeDnsServer,
#                        e.byref (DataSize),
#                        e.cast (e.byref (DnsAddr), e.PVOID)
#                        )
#

# Dumpped information
#
# for Dns in DnsAddr:
#   print "   DnsAddr:"
#   for Addr in Dns.Addr:
#     print "%02X " % Addr,
#   print

6/30/2018

Load and run EDK2 DuetPkg from DOS

Made some modification from EDK2 DuetPkg.
Its purpose is as title and with this benefit:
    DuetPkg can be load/run without destroying boot storage.

The project name is LoadDuetPkg at https://github.com/EfiPy/LoadDuetPkg
For more detail, please reference GitHub.

12/12/2016

Calling User specified PROTOCOL from Python

Suppose:
There is PORTOCOL which is not defined in UEFI/PI and is built in BIOS image.
This PROTOCOL interface is known by C language header file:

#ifndef _XYZ_DXE_H_
#define _XYZ_DXE_H_

#define USER_XYZ_PROTOCOL_GIUD \
  { \
    0x2a339172, 0x7ef6, 0x4f2b, { 0x95, 0xb9, 0x83, 0xf2, 0x15, 0x18, 0xeb, 0xf7} \
  }


typedef struct _USER_XYZ_PROTOCOL USER_XYZ_PROTOCOL;

typedef
EFI_STATUS
(EFIAPI *USER_XYZ_GET_VERSION)(
  IN  CONST USER_XYZ_PROTOCOL     *This,
  OUT UINT64                      *VersionSize
  );

typedef
EFI_STATUS
(EFIAPI *USER_XYZ_DUMMY)(
  VOID
  );

///
/// XYZ Protocol structure
///
struct _USER_XYZ_PROTOCOL {
  USER_XYZ_GET_VERSION    GetVersion;
  USER_XYZ_DUMMY          Dummy;
};

#endif // _XYZ_DXE_H_


PROTOCOL's EfiPy2 form and How to use it:
#
# xyzProtocol.py
#

#
# XYX PROTOCOL declare in EfiPy2 format
#
from EfiPy2 import *

#
# XYZ protocol GUID
#
# #define USER_XYZ_PROTOCOL_GIUD \
#   { \
#     0x2a339172, 0x7ef6, 0x4f2b, { 0x95, 0xb9, 0x83, 0xf2, 0x15, 0x18, 0xeb, 0xf7} \
#   }
# EFI_GUID gUserXyzProtocolGuid = USER_XYZ_PROTOCOL_GIUD;
#
gUserXyzProtocolGuid                 = \
  EFI_GUID (0x2a339172, 0x7ef6, 0x4f2b, (0x95, 0xb9, 0x83, 0xf2, 0x15, 0x18, 0xeb, 0xf7))

#
# XYZ protocol declare
#
# typedef struct _USER_XYZ_PROTOCOL USER_XYZ_PROTOCOL;
#
class USER_XYZ_PROTOCOL (Structure):
  pass

#
# USER_XYZ_GET_VERSION function declare
#
# typedef
# EFI_STATUS
# (EFIAPI *USER_XYZ_GET_VERSION)(
#   IN  CONST USER_XYZ_PROTOCOL     *This,
#   OUT UINT64                      *VersionSize
#   );
#
USER_XYZ_GET_VERSION = CFUNCTYPE (
  EFI_STATUS,
  POINTER (USER_XYZ_PROTOCOL),
  POINTER (UINT64)
  )

#
# USER_XYZ_DUMMY function declare
#
# typedef
# EFI_STATUS
#   (EFIAPI *USER_XYZ_DUMMY)(
#   VOID
#   );
#
# Return type: EFI_STATUS
# Input parameter: None
#
USER_XYZ_DUMMY = CFUNCTYPE (
  EFI_STATUS
  )

#
# XYZ Protocol structure
#
# struct _USER_XYZ_PROTOCOL {
#   USER_XYZ_GET_VERSION    GetVersion;
#   USER_XYZ_DUMMY          Dummy;
# };
#
USER_XYZ_PROTOCOL._fields_ = [
  ("GetVersion",  USER_XYZ_GET_VERSION),
  ("Dummy",       USER_XYZ_DUMMY)
  ]


#
# Test program for verifying protocol conversation
#
if __name__ == '__main__':

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

  if Status != 0x00:
    print "Locate Protocol Error (Status:%x)" % Status
    exit (0)

  XyzProtocol = cast (Interface, POINTER(USER_XYZ_PROTOCOL))

  Version = UINT64(0)

  Status = XyzProtocol[0].GetVersion (XyzProtocol, byref(Version))

  print "Get Version: %x (Status:%x)" % (Version.value, Status)


Advanced
After this EfiPy2 protocol program test is done, it can be put into package folder, including __init__.py.

Setting PYTHONPATH uefi shell environment variable lets user specified protocol in anywhere.

Example: Folder fs0:\Xyz includes xyzProtocol.py and __init__.py 

set PYTHONPATH fs0:\Xyz

USER_XYZ_PROTOCOL can be called from anywhere by

import xyzProtocol

Q&A: Should EfiPy2 programmer needs to reference protocol implementation source code?
Answer: 
No, it is the same as EFI caller program, EfiPy2 programmer needs Protocol header file and transfer it to Python code, only.

Q&A: Should python.efi needs to be compiled, again, for user specified PROTOCOL?
Answer:
No, python.efi includes ctypes.
ctypes for UEFI is a foreign function library for Python. It provides C compatible data types, and allows calling functions in UEFI PROTOCOL. It can be used to wrap PROTOCOLs in pure Python. (ref. from Here)