【问题标题】:Python3 ctypes c_unit32 endiannessPython3 ctypes c_unit32 字节序
【发布时间】:2017-07-19 11:52:14
【问题描述】:

我正在尝试将 PCI 配置空间数据加载到 python 中进行评估,但在使用 c_unit32 作为 BAR0 时遇到了问题。我设法简化了问题/脚本以显示 c_uint16 的行为符合我的预期,但 c_uint32 失败了。 Bar0 必须是实际脚本中的 c_unit32,Bar0 被解码为一个单独的结构,它使用位 0-13 用于各种字段,然后位 14:31 用于较低的 BAR。

在脚本中,数据是从 /sys/pci/bus/devices/x/config 加载的,所以返回为一串十六进制字符,这在示例中通过加载一个较小的字符串来模拟字段数

预期:

输入字符串:“86802010f6710000”

供应商 ID:0x8086
设备 ID:0x1020
Bar0 : 0x71f60000

实际:

输入字符串:“86802010f6710000”

供应商 ID:0x8086
设备 ID:0x1020
Bar0 : 0x71f6

VendorID 和 DeviceID 字段已正确交换。我假设“0000”正在被字节交换并被放在 f671 的前面,然后 f671 被字节交换为 71f6。然后消除前导 00,创建“0x71f6”。如果我使用变成 0x171f6 的“f6710100”,则可以确认这一点。


当我使用 c_uint32 时,如何确保它被正确解释为 0x71f60000?


代码:

from ctypes import *


class PCICfg(Structure):

    _pack_ = 1
    _fields_ = [
                ("VendorID", c_uint16),
                ("DeviceID", c_uint16),
                ("Bar0",     c_uint32),
               ]


class PCIUnion(Union):

    _pack_ = 1
    _fields_ = [
                ("ConfigSpace", PCICfg),
                ("Bytes",       c_ubyte * sizeof(PCICfg))
               ]


    def from_str(self, input):

        print("Input String: ", input)

        hex_data = bytearray.fromhex(input)

        for x in range(0, len(hex_data)):
            self.Bytes[x] = hex_data[x]


if __name__ == '__main__':

    cfg = PCIUnion()
    cfg.from_str("86802010f6710100")

    print("VID: %s" % hex(cfg.ConfigSpace.VendorID))
    print("DID: %s" % hex(cfg.ConfigSpace.DeviceID))
    print("BA0: %s" % hex(cfg.ConfigSpace.Bar0))

【问题讨论】:

    标签: python python-3.x ctypes


    【解决方案1】:

    您看到的是正确的 little-endian 32 位输入结果,但如果您的输入确实是 little-endian 16 位字的十六进制表示,那么就这样处理:

    from ctypes import *
    from binascii import unhexlify
    
    class PCICfg(Structure):
        _pack_ = 1
        _fields_ = [("VendorID", c_uint16),
                    ("DeviceID", c_uint16),
                    ("Bar0Hi", c_uint16),
                    ("Bar0Lo", c_uint16)]
    
    class PCIUnion(Union):
        _pack_ = 1
        _fields_ = [("ConfigSpace", PCICfg),
                    ("Bytes", c_ubyte * sizeof(PCICfg))]
    
        def from_str(self, inp):
            print("Input String: ", inp)
            self.Bytes[:] = unhexlify(inp)
    
    if __name__ == '__main__':
        cfg = PCIUnion()
        cfg.from_str("86802010f6710100")
        print("VID: {:#04x}".format(cfg.ConfigSpace.VendorID))
        print("DID: {:#04x}".format(cfg.ConfigSpace.DeviceID))
        print("BA0: {:#04x}{:04x}".format(cfg.ConfigSpace.Bar0Hi,cfg.ConfigSpace.Bar0Lo))
    
    Input String:  86802010f6710100
    VID: 0x8086
    DID: 0x1020
    BA0: 0x71f60001
    

    【讨论】:

    • @Martin,我建议将from_str 设为一个返回cls.from_buffer_copy(unhexlify(inp))classmethod 构造函数。
    猜你喜欢
    • 2021-07-21
    • 1970-01-01
    • 2019-03-16
    • 2021-10-06
    • 1970-01-01
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多