Python3 ctypes c_unit32 endianness

时间:2017-07-19 11:52:15

标签: python python-3.x ctypes

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

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

预期:

输入字符串:“86802010f6710000”

VendorID:0x8086
  DeviceID:0x1020
  Bar0:0x71f60000

实际:

输入字符串:“86802010f6710000”

VendorID:0x8086
  DeviceID:0x1020
  Bar0:0x71f6

正确交换VendorID和DeviceID字段。我假设“0000”正在进行字节交换并被置于f671的前面,然后f671被字节交换为71f6。然后消除前导00,创建“0x71f6”。如果我使用“f6710100”变为0x171f6,则确认。

我如何确保何时使用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))

1 个答案:

答案 0 :(得分:2)

您所看到的是输入的正确的小端32位结果,但如果您的输入实际上是小端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