Exploring the xclbin File Format of FPGA (Part 2)

Click the blue text to follow us

Exploring the xclbin File Format of FPGA (Part 2)

Exploring the xclbin File Format of FPGA (Part 2)

[[0x1 Introduction]]

[[0x2 Advanced Features of xclbin Files]]

[[0x3 Security Mechanisms of xclbin Files]]

[[0x4 Loading and Verification of xclbin Files]]

[[0x5 Toolchain Analysis of xclbin Files]]

[[0x6 Conclusion]]

0x1 Introduction

In the previous article, we delved into the basic structure of the xclbin file and the parsing methods for its core sections. This article will continue to explore the advanced features of the xclbin file, including its security verification mechanisms, runtime loading processes, toolchain implementations, and practical application scenarios. By combining the 010 Editor template and XRT source code, we will comprehensively analyze the technical details of the xclbin file format.

0x2 Advanced Features of xclbin Files

0x2.1 Deep Integration of 010 Editor Template

Based on the xclbin.bt template, we can achieve complete visual parsing of the xclbin file. This template not only defines the basic structure but also provides a dynamic section parsing mechanism:

// From xclbin.bt template file - Dynamic section parsingfor (uIndex=0; uIndex < root.m_header.m_numSections; uIndex++) {    offset = root.m_sections[uIndex].m_sectionOffset;    size = root.m_sections[uIndex].m_sectionSize;
    if(size <= 0)        continue;
    switch(root.m_sections[uIndex].m_sectionKind) {        case EMBEDDED_METADATA:                 //2 - Embedded metadata section            local string embname = root.m_sections[uIndex].name;            FSeek(offset);            string Embmeta <comment=Str(embname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;        case MEM_TOPOLOGY:                      //6 - Memory topology section            local string memname = root.m_sections[uIndex].name;            FSeek(offset);            mem_topology MemTopology <comment=Str(memname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;        case CONNECTIVITY:                      //7 - Connectivity section            local string connname = root.m_sections[uIndex].name;            FSeek(offset);            connectivity Connectivitys <comment=Str(connname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;        case IP_LAYOUT:                         //8 - IP core layout section            local string ipname = root.m_sections[uIndex].name;            FSeek(offset);            ip_layout IpLayout <comment=Str(ipname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;        case AIE_PARTITION:                     //32 - AIE partition section            local string aiepartname = root.m_sections[uIndex].name;            FSeek(offset);            aie_partition aiep <comment=Str(aiepartname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;        default:            local string defaultnname = root.m_sections[uIndex].name;            FSeek(offset);            char defaultbuffer[size] <comment=Str(defaultnname),bgcolor=0xFFF0F5,optimize=false>;            FSeek(offset+size);            break;    }}

0x2.2 Deep Analysis of AIE Partition Structure

AIE (AI Engine) is an important component in Xilinx’s next-generation FPGA, and its partition structure is specifically defined in the xclbin:

// From xclbin.bt template file - AIE partition structuretypedef struct {    local quad off = FTell();    char schema_version;             // Group schema version (default 0)    char padding0[3];                // 3-byte padding to ensure 4-byte alignment    uint32 mpo_name;                  // Name of the aie_partition     uint32 operations_per_cycle;      // Operations per cycle. Used later to create TOPS    char padding[4];                 // 4-byte padding to ensure 8-byte alignment    uint64 inference_fingerprint <format=hex>;     // The unique hash value of the inference function    uint64 pre_post_fingerprint <format=hex>;      // The unique hash value of pre post     aie_partition_info info;     // Partition information    array_offset aiepdi_info;        // PDI Array (aie_partition_info)    char reserved[56];               // 56-byte reserved field, filled with 0xFF    FSeek(off+mpo_name);    local string objname = ReadString(FTell(),16);    FSeek(off+info.start_columns.offset);    uint16 start_col_list[info.start_columns.size] <comment=Str(objname)>;    FSeek(off+aiepdi_info.offset);    aie_pdi aiepdi[aiepdi_info.size];    FSeek(off+aiepdi.cdo_groups.offset);    cdo_group cdop[aiepdi.cdo_groups.size] <optimize=false>;    FSeek(off+cdop.dpu_kernel_ids.offset);    uint64 kernel_idp[cdop.dpu_kernel_ids.size];}aie_partition;

0x2.3 Connectivity and Memory Mapping

The CONNECTIVITY section defines the connection relationships between IP cores and memory, which is crucial for the operation of the FPGA system:

// From xclbin.bt template file - Connectivity structuretypedef struct {    int32 arg_index;                     // From 0 to n, may not be contiguous as scalars skipped    int32 m_ip_layout_index;             // index into the ip_layout section. ip_layout.m_ip_data[index].m_type == IP_KERNEL    int32 mem_data_index;                // index of the m_mem_data . Flag error is m_used false.}connection;typedef struct {    int64 m_count;    connection m_connection[m_count];}connectivity;

0x2.4 Session Parsing Mechanism

XRT provides a complete section parsing mechanism that supports dynamic section type registration:

// From xrt/src/runtime_src/tools/xclbinutil/Section.hclass Section {    enum class FormatType {        undefined,        unknown,        raw,        json,        html,        txt    };    class SectionInfo {        axlf_section_kind eKind;         // Section enumeration value        std::string name;                // Section name        Section_factory sectionCtor;     // Section constructor        std::string nodeName;            // JSON node name        bool supportsSubSections;        // Supports sub-sections        bool supportsIndexing;           // Supports indexing        std::vector<FormatType> supportedAddFormats;   // Supported add formats        std::vector<FormatType> supportedDumpFormats;  // Supported dump formats        std::vector<std::string> subSections;          // Supported sub-sections    };};

0x3 Security Mechanisms of xclbin Files

0x3.1 Digital Signature and Verification

The xclbin file supports the PKCS#7 digital signature mechanism, ensuring the integrity and trustworthiness of the file. The signature information is stored in the m_keyBlock field of the axlf structure:

// From xrt/src/runtime_src/tools/xclbinutil/XclBinSignature.cxxvoid getXclBinPKCSStats(const std::string& _xclBinFile, XclBinPKCSImageStats& _xclBinPKCSImageStats) {    // Read xclbin header    axlf xclBinHeader;    ifXclBin.read((char*)&xclBinHeader, sizeof(axlf));
    // Verify magic number    std::string sMagicValue = (boost::format("%s") % xclBinHeader.m_magic).str();    if (sMagicValue.compare("xclbin2") != 0) {        auto errMsg = boost::format("ERROR: The XCLBIN appears to be corrupted. Expected magic value: 'xclbin2', actual: '%s'") % sMagicValue;        throw std::runtime_error(errMsg.str());    }
    // Get signature information - check signature length field (-1 indicates no signature)    if (xclBinHeader.m_signature_length != -1) {        _xclBinPKCSImageStats.signature_size = xclBinHeader.m_signature_length;        _xclBinPKCSImageStats.signature_offset = xclBinHeader.m_header.m_length - xclBinHeader.m_signature_length;    }}

0x3.2 Signature Verification Process

The XRT runtime automatically performs signature verification when loading the xclbin file to ensure the file has not been tampered with:

// From xrt/src/runtime_src/tools/xclbinutil/XclBinSignature.cxxvoid verifyXclBinImage(const std::string& _fileOnDisk, const std::string& _sCertificate, bool _bEnableDebugOutput) {    // Check if the file is PKCS signed    XclBinPKCSImageStats xclBinPKCSStats = { 0 };    getXclBinPKCSStats(_fileOnDisk, xclBinPKCSStats);
    if (xclBinPKCSStats.is_PKCS_signed == false) {        throw std::runtime_error("ERROR: Xclbin image is not signed. File: '" + _fileOnDisk + "'");    }
    // Use OpenSSL for PKCS#7 verification    PKCS7* p7 = d2i_PKCS7_bio(bmSignature, NULL);    if (p7 == NULL) {        auto errMsg = boost::format("ERROR: Signature at offset 0x%lx is not valid.") % pXclBinHeader->m_header.m_length;        throw std::runtime_error(errMsg.str());    }
    // Verify signature    if (!PKCS7_verify(p7, ca_stack, store, bmImage, NULL, PKCS7_DETACHED | PKCS7_BINARY | PKCS7_NOINTERN)) {        std::cout << "Signed xclbin archive verification [FAILED]" << std::endl;    } else {        std::cout << "Signed xclbin archive verification [SUCCESSFUL]" << std::endl;    }}

0x3.3 Security Policies and Access Control

The xclbin file also supports UUID-based access control, implemented through the m_interface_uuid field:

// From xclbin.bt template file - UUID access controltypedef struct {    unsigned char m_interface_uuid[16] <comment="Interface uuid of this xclbin",format=hex>;  // 16-byte UUID for access control    // ... other fields}axlf_header;

0x4 Loading and Verification of xclbin Files

0x4.1 File Loading Process

The loading of the xclbin file is a complex process involving file verification, memory allocation, section parsing, and several other steps. The loading process begins in user space and is passed to kernel space through the DRM interface:

// From xrt/src/runtime_src/core/edge/drm/zocl/edge/zocl_edge_xclbin.cint zocl_xclbin_read_axlf(struct drm_zocl_dev *zdev, struct drm_zocl_axlf *axlf_obj, struct kds_client *client) {    struct axlf axlf_head;    struct axlf *axlf = NULL;    long axlf_size;    char __user *xclbin = NULL;
    // Copy axlf header from user space    if (copy_from_user(&axlf_head, axlf_obj->za_xclbin_ptr, sizeof(struct axlf))) {        DRM_WARN("copy_from_user failed for za_xclbin_ptr");        return -EFAULT;    }
    // Verify magic number - check file identifier "xclbin2\0"    if (memcmp(axlf_head.m_magic, "xclbin2", 8)) {        DRM_WARN("xclbin magic is invalid %s", axlf_head.m_magic);        return -EINVAL;    }
    // Calculate full axlf size    size_of_header = sizeof(struct axlf_section_header);    num_of_sections = axlf_head.m_header.m_numSections - 1;    axlf_size = sizeof(struct axlf) + size_of_header * num_of_sections;
    // Allocate kernel memory    axlf = vmalloc(axlf_size);    if (!axlf) {        DRM_WARN("read xclbin fails: no memory");        return -ENOMEM;    }
    // Copy full axlf data    if (copy_from_user(axlf, axlf_obj->za_xclbin_ptr, axlf_size)) {        DRM_WARN("read xclbin: fail copy from user memory");        vfree(axlf);        return -EFAULT;    }
    return 0;}

0x4.2 Section Parsing and Registration

During the loading process, each section needs to be parsed and registered with the corresponding management module. This process is dynamic and supports the extension of different section types:

// From xrt/src/runtime_src/core/edge/drm/zocl/common/zocl_xclbin.cint populate_slot_specific_sec(struct drm_zocl_dev *zdev, struct axlf *axlf, char __user *xclbin, struct drm_zocl_slot *slot) {    struct mem_topology     *topology = NULL;    struct ip_layout        *ip = NULL;    struct debug_ip_layout  *debug_ip = NULL;    struct connectivity     *connectivity = NULL;    struct aie_metadata      aie_data = { 0 };    uint64_t                 size = 0;    // Parse IP_LAYOUT section    size = zocl_read_sect(IP_LAYOUT, &ip, axlf, xclbin);    if (size <= 0) {        if (size != 0)            return size;    } else if (sizeof_section(ip, m_ip_data) != size)        return -EINVAL;    // Parse DEBUG_IP_LAYOUT section    size = zocl_read_sect(DEBUG_IP_LAYOUT, &debug_ip, axlf, xclbin);    if (size <= 0) {        if (size != 0)            return size;    } else if (sizeof_section(debug_ip, m_debug_ip_data) != size)        return -EINVAL;    // Parse AIE_METADATA section    size = zocl_read_sect(AIE_METADATA, &aie_data.data, axlf, xclbin);    if (size < 0)        return size;    aie_data.size = size;    // Parse CONNECTIVITY section    size = zocl_read_sect(CONNECTIVITY, &connectivity, axlf, xclbin);    if (size <= 0) {        if (size != 0)            return size;    } else if (sizeof_section(connectivity, m_connection) != size)        return -EINVAL;    // Parse MEM_TOPOLOGY section    size = zocl_read_sect(MEM_TOPOLOGY, &topology, axlf, xclbin);    if (size <= 0) {        if (size != 0)            return size;    } else if (sizeof_section(topology, m_mem_data) != size)        return -EINVAL;    // Register to slot    write_lock(&zdev->attr_rwlock);    slot->ip = ip;    slot->debug_ip = debug_ip;    slot->aie_data = aie_data;    slot->connectivity = connectivity;    slot->topology = topology;    write_unlock(&zdev->attr_rwlock);
    return 0;}

0x4.3 Bitstream Header Parsing

The bitstream data in the xclbin file requires a dedicated parser to extract design information. This process involves complex binary format parsing:

// From xrt/src/runtime_src/core/common/drv/xrt_xclbin.cint xrt_xclbin_parse_header(const unsigned char *data, unsigned int size, struct XHwIcap_Bit_Header *header) {    unsigned int i;    unsigned int len;    unsigned int tmp;    unsigned int index;    /* Start Index at start of bitstream */    index = 0;    /* Initialize HeaderLength. If header returned early indicates failure. */    header->HeaderLength = XHI_BIT_HEADER_FAILURE;    /* Get "Magic" length */    header->MagicLength = data[index++];    header->MagicLength = (header->MagicLength << 8) | data[index++];    /* Read in "magic" - Verify alternating magic byte sequence */    for (i = 0; i < header->MagicLength - 1; i++) {        tmp = data[index++];        if (i%2 == 0 && tmp != XHI_EVEN_MAGIC_BYTE)  // Even positions must be 0xAA            return -1;   /* INVALID_FILE_HEADER_ERROR */        if (i%2 == 1 && tmp != XHI_ODD_MAGIC_BYTE)   // Odd positions must be 0x55            return -1;   /* INVALID_FILE_HEADER_ERROR */    }    /* Read null end of magic data. */    tmp = data[index++];    /* Read 0x01 (short) - Fixed identifier */    tmp = data[index++];    tmp = (tmp << 8) | data[index++];    /* Check the "0x01" half word */    if (tmp != 0x01)        return -1;   /* INVALID_FILE_HEADER_ERROR */    /* Read 'a' - Fixed character identifier */    tmp = data[index++];    if (tmp != 'a')        return -1;    /* INVALID_FILE_HEADER_ERROR  */    /* Get Design Name length */    len = data[index++];    len = (len << 8) | data[index++];    /* allocate space for design name and final null character. */    header->DesignName = vmalloc(len);    /* Read in Design Name */    for (i = 0; i < len; i++)        header->DesignName[i] = data[index++];    if (header->DesignName[len-1] != '\0')        return -1;    return 0;}

0x4.4 Runtime Verification and Error Handling

The xclbin file requires continuous verification at runtime to ensure system stability:

// From xclbin.bt template file - Mirror data verificationstring mirroData <comment="XCLBIN_MIRROR",fgcolor=cBlue,bgcolor=0xFFF0F5,optimize=false>;if (Strstr(mirroData, "XCLBIN_MIRROR_DATA_START") == -1)  // Check mirror data start identifier{    Printf("ERROR: Mirror backup data not found in given file.\n");    return 2;}if (Strstr(mirroData, "XCLBIN_MIRROR_DATA_END") == -1)    // Check mirror data end identifier{    Printf("ERROR: Mirror backup data not well formed in given file.\n");    return 3;}

0x5 Toolchain Analysis of xclbin Files

0x5.1 xclbinutil Tool

XRT provides a complete toolchain for processing xclbin files, with xclbinutil being the most important tool. It supports the creation, modification, verification, and conversion of xclbin files:

// From xrt/src/runtime_src/tools/xclbinutil/XclBinClass.cxxclass XclBin {    public:        // Add section        void addSection(const std::string& _sSectionName, const std::string& _sFormatType, const std::string& _sInputFile);
        // Dump section        void dumpSection(const std::string& _sSectionName, const std::string& _sFormatType, const std::string& _sOutputFile);
        // Validate xclbin file        void validateXclBin();
        // Sign xclbin file        void signXclBin(const std::string& _sPrivateKey, const std::string& _sCertificate);
        // Verify signature        void verifyXclBin(const std::string& _sCertificate);};

0x5.2 Section Processing Mechanism

Each section type has a corresponding processing class that supports various input and output formats. This design provides excellent extensibility for the toolchain:

// From xrt/src/runtime_src/tools/xclbinutil/Section.hclass Section {    public:        // Supported format types        enum class FormatType {            undefined,            unknown,            raw,            json,            html,            txt        };
        // Create section from JSON        virtual void marshalFromJSON(const boost::property_tree::ptree& _ptSection, std::ostringstream& _buf) const = 0;
        // Dump to JSON        virtual void marshalToJSON(const boost::property_tree::ptree& _ptSection, std::ostringstream& _buf) const = 0;
        // Read from binary        virtual void readXclBinBinary(std::istream& _iStream, const axlf_section_header& _sectionHeader) = 0;
        // Write to binary        virtual void writeXclBinBinary(std::ostream& _oStream, const axlf_section_header& _sectionHeader) = 0;};

0x6 Conclusion

Through an in-depth analysis of the xclbin file format, we have gained a comprehensive understanding of its technical characteristics as an FPGA application container. The xclbin file adopts a modular section architecture, supporting 35 different section types, each with specific functions, and implements a flexible file organization method through the axlf header and section headers, supporting dynamic section registration and parsing. In terms of security mechanisms, the xclbin file integrates the PKCS#7 digital signature mechanism, storing signature information in the m_keyBlock field and specifying the signature length in the m_signature_length field, ensuring the integrity and trustworthiness of the file. The loading process involves multiple steps, including file verification, memory allocation, and section parsing, with the XRT runtime providing a complete loading interface that supports loading xclbin files from various sources, including files and memory handles. Additionally, XRT offers a complete toolchain for processing xclbin files, including the xclbinutil tool and the 010 Editor template, supporting the creation, modification, verification, and parsing of xclbin files. The xclbin file format serves as a core technology for FPGA applications, providing a standardized application deployment format for the FPGA ecosystem, supporting cross-platform and cross-vendor FPGA application deployment, and holding significant technical value and practical significance. By deeply understanding the technical details of the xclbin file format, we can better leverage the powerful computing capabilities of FPGAs to provide high-performance, low-power solutions for various application scenarios.

—— ending ——

Previous Highlights Collection

● Exploring the xclbin file format of FPGA

● Security laboratory experts participated in the compilation of the “Technical Requirements for Information Security Penetration Testing” group standard officially released

● When APK is no longer pure Java: A penetration testing guide for embedded non-Java code

● A brief discussion on Android security testing: Smali dynamic debugging

● Lenovo’s Global Security Laboratory appeared at the International Hacker Marathon Cybersecurity Conference, analyzing AI digital human threats and full-link defense

● In-depth analysis: Design and implementation of device fingerprinting

● Java deserialization security: CC6 chain analysis

● Lenovo joins the anti “unboxing” technology working group to strengthen personal information security defenses with technology

● Don’t let permission configuration become a “backdoor”: In-depth analysis of Windows access control mechanisms and security design strategies

● Lenovo’s Global Security Laboratory appeared at WAIC 2025, showcasing cutting-edge technologies for AI model security

Leave a Comment