bits-1081 released with these changes:
The "ctypes. ctypes run. run types run" release.
This release introduces preliminary support for the Python ctypes module in EFI builds. This includes the initial infrastructure to compile libffi as part of BITS.
ctypes data types, ctypes structures, and read/write access to memory
work. This replaces many uses of bits.memory
, struct.pack
,
struct.unpack
, and the BITS unpack
module. In particular, the use
of ctypes data types and structures allows round-trip conversions from
structures in memory to Python data types and back, generally without
making copies.
This initial implementation provides enough support for all the data structures in the efi module, which has now completely switched over to ctypes-based data types and structures.
Notable limitations:
- No support for non-EFI builds yet, because GRUB uses stdcall and regparm=3 for PC BIOS builds, which libffi does not support on non-Windows systems.
- Function calls to EFI functions still require
efi.call
; the ctypes-based FFI does not yet work, as it does not understand the EFI calling convention. dlopen
does not work, so there's no way to obtain pointers to existing C functions to call.
Note that to support this change, the version of Python built into BITS
now internally uses UTF-16 (2-byte characters) rather than UCS-4 (4-byte
characters), to match EFI. This allows the use of the ctypes functions
for the C wchar_t
type, rather than hand-rolled functions for two-byte
Unicode. Python still has full support for all of Unicode, including
characters outside the Basic Multilingual Plane; this just changes the
internal representation. However, attempting to use characters outside
the BMP in EFI calls may or may not work, depending on your firmware;
your mileage may vary.
This release also introduces support for reading and writing files using
EFI. On EFI systems, BITS now has full support for writing arbitrary
files to a FAT filesystem. The new efi.get_boot_fs()
function will
retrieve the filesystem BITS booted from, as an efi_file
, a new Python
file-like object. In addition to the usual file methods, an efi_file
provides methods to open and create files and directories. For example:
import efi
root = efi.get_boot_fs()
newdir = root.mkdir("newdir")
newfile = newdir.create("newfile")
newfile.write("Hello world!\n")
Or, chaining the calls together (convenient for command-line usage):
efi.get_boot_fs().mkdir("newdir").create("newfile").write(data)
The new functions acpi.efi_save_tables()
and efi.save_tables()
use
this new filesystem write capability to save copies of ACPI and EFI
tables, for later inspection.
Note that EFI firmware typically only supports FAT filesystems, not
iso9660 (the filesystem used on optical media). The BITS .iso images,
even when imaged to a USB disk, keep most of their files in an iso9660
filesystem, with the exception of a small FAT filesystem used to store
GRUB itself as an EFI binary. Thus, get_boot_fs()
will not produce
the expected results when booting from an optical disc or from a disk
created from a BITS .iso; for full read/write support, create a
FAT-based BITS disk, following the procedure in INSTALL.txt.
This release adds support for many new EFI protocols:
efi: Add read/write file support using FileProtocol, including a file-like object
The
efi_file
wrapper includes the standard Python file-like methods (read
,write
,seek
,tell
,close
,flush
), EFI-specific properties (file_info
,file_system_info
,volume_label
) and methods (delete
), and methods to create or open anotherefi_file
relative to a directory (open
,create
,mkdir
).Also add a definition of the EFI SimpleFileSystemProtocol to open a block device, with a
root
property to get the root directory as anefi_file
.Add a
get_boot_fs()
function to return the filesystem BITS booted from, obtained via the DeviceHandle of the LoadedImageProtocol on the image handle. Useful as the root for writing files.efi: Add DevicePathProtocol and DevicePathToTextProtocol
DevicePathToTextProtocol includes helpers to transform the returned paths into Python unicode strings, and then free the original memory.
efi: Add LoadedImageProtocol
Other changes in this release:
python: Support the zlib module
bits.present, mkpresent: Use zlib to compress and decompress slide images
Provides an order of magnitude improvement to disk usage and load time.
acpi: Add an
efi_save_tables
utility function to save ACPI tables to filesAs the name suggests, this function only works on EFI, since it uses the EFI file write support.
In addition to the binary dumps, this also includes text decodes of selected structures, and enough address information to recreate the tables in memory.
efi: Add a function
efi.save_tables()
to save the core EFI tables to filesefi: As a workaround for limitations in the internal EFI function call interface, add a compatibility layer for 64-bit arguments on 32-bit platforms. Wrap 64-bit arguments in
efi.split64()
, and they will automatically be split into pairs of 32-bit arguments on 32-bit platforms, for compatibility with the currentefi.call
interface.Add EFI tests. The first round of tests verifies the CRCs of the core EFI tables.
efi: Add a base class for EFI protocols
Protocols are ctypes structures with an associated GUID; they provide a
.from_handle
classmethod to get the protocol from an EFI handle (via OpenProtocol) and wrap it in the protocol class.efi: Add more known UUIDs
efi: When printing structures, format pointers and unsigned types as hex, and list out the contents of arrays.
efi: Various new helper functions:
- Add a helper function
check_status
to throw an exception for !=EFI_SUCCESS
- Add a helper check_error_value to handle non-status return values.
Some EFI functions return a non-status return value, but still use
the
EFI_ERROR
bit to indicate an error. Add a helper that checks only that bit, and otherwise returns the value for subsequent use. - Add a
locate_handles
helper to call LocateHandle with a given GUID. This helper handles the two-pass memory allocation, and returns a ctypes array of handles. - Add helper functions to compute table CRC32 values. These compute the CRC32 as if the table's CRC32 field is 0, and then compare the result to the table's actual CRC32 field.
- Add a helper function
efi.to_bytes
to convert a ctypes structure to raw bytes
- Add a helper function
README.Developers.txt: Document Python patches for ctypes and libffi