bits-1151 released with these changes:

The "I FFI, UEFI, we all FFI for EFI" release.

BITS now supports making EFI calls via the Python ctypes module, rather than manually using efi.call. This provides simplified call syntax, type safety, better (reference-counted) memory lifetime handling, bounds checking, and the ability to have EFI call Python callbacks.

All EFI protocols, functions, and types have been converted to use ctypes.

This also provides automatic conversions to and from Python types as appropriate. For instance, functions declared to accept a c_wchar_p (a Unicode string) accept Python string and unicode objects:

out = efi.system_table.ConOut.contents
out.OutputString(out, "Hello world!\r\n")
  • Add support for the 64-bit EFI calling convention in ctypes

    Ship a separate copy of libffi with 64-bit EFI support added, and change Python's _ctypes module to support that calling convention.

    Add the uintptr_t and intptr_t types to our stdint.h, since libffi needs uintptr_t.

  • Convert all EFI functions, structure, and protocols to ctypes

    Now that ctypes can call EFI functions, convert all functions to use it, along with the corresponding types and protocols. This significantly improves type safety, memory lifetime handling, bounds checking, and similar.

    In particular, code should now almost never use from_address or addressof, since those produce raw addresses that may outlive the objects they point to; code using from_address should now use from_buffer or similar, and code using addressof should use byref or similar.

    Define a new type EFIFUNCTYPE, analogous to ctypes.CFUNCTYPE, for calls using the EFI calling convention. For convenience, provide a wrapper efi.FUNC that assumes a return type of EFI_STATUS (overridable with a keyword parameter ret).

    To simplify the process of translating EFI functions and structures from specifications, define appropriate EFI type aliases for ctypes types. For instance, EFI extensively uses the type UINTN for "an integer the size of a pointer", so the efi module defines that type as c_ulong.

    Using ctypes function types also enables many convenient conversions. For example, a function taking a parameter of type c_wchar_p can accept a Python string or unicode object. See the ctypes documentation for more details.

    When defining function parameter and return types, note that the ctypes types c_char_p and c_wchar_p have additional magic behavior above and beyond a normal pointer, to transparently accept and return strings. This behavior can be convenient, but it means that an EFI function specified to accept or return a pointer to CHAR16 may want to use either POINTER(CHAR16) or EFI_STRING (AKA c_wchar_p) as its type, depending on the desired semantic behavior. Use POINTER(CHAR16) (and create_unicode_buffer) for a pointer that EFI will fill in (since passing a temporary object converted from a Python unicode object would not produce useful results), or for a returned pointer that the caller must free via the EFI FreePool or similar (since the automatic conversion of return types from c_wchar_p to a Python unicode object would discard the pointer that needs freeing).

    EFIException now decodes known EFI error codes as symbolic names, in addition to showing the hex value of all error codes.

    Since efi now makes much more extensive use of ctypes types, switch from import ctypes to from ctypes import *. Similarly, bits.present does from efi import * to get the EFI types. In general, modules that just call efi functions should import efi, but modules defining new EFI protocols or structures should from efi import *.

    efi.call, and the associated split64() magic for 64-bit parameters on 32-bit EFI, are no more. They will not be mourned.

  • Backport a grub change to fix a build failure on systems with new flex

    With current versions of flex, grub failed to build with this error:

      grub_script.yy.c:2367:13: error: 'yy_fatal_error' defined but not used [-Werror=unused-function]
       static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
    

    Fix that by backporting the change from git commit 9cc836a27be4a95f6f7bfd5b6bc099801645c0ea to disable additional warnings for the flex-generated lexer.

  • Disable -Wunused-value for Python

    Current Python on current GCC generates a -Wunused-value warning on uses of the PyObject_INIT macro, because it expands to a comma expression where the rightmost value goes unused if nothing looks at the return value. This warning turns into an error because of -Werror.