python mmap在写入时跳过每隔一个字节

k3t*_*hup 7 python mmap python-2.7

在写入内存(/ dev/mem)时,我在python中使用mmap时遇到了一个奇怪的问题.要清楚,阅读是以同样的方式完成的,并且工作正常.但是当涉及到写入时,似乎每个第二个字节都是不可写的.

恩.

 when I read i get 
 addr 0x200 val 0x1234
 but when I try to write
 addr 0x200 val 0x4321
 what really is written is
 addr 0x200 val 0x0021
Run Code Online (Sandbox Code Playgroud)

当我尝试逐字节写入时,同样的情况发生.恩.

write:
addr 0x200 0x43
addr 0x201 0x21
I get
addr 0x200 0x00
addr 0x201 0x21
Run Code Online (Sandbox Code Playgroud)

码:

class Pydump:
    def __init__(self, addr, length = 1, word_size = 4, filename = '/dev/mem'):
        if addr < 0 or length < 0: raise ValueError('Address or length invalid')
        self._verbose = verbose

        self.word_size = word_size
        self.mask = ~(self.word_size - 1)
        self.base_addr = addr & ~(mmap.PAGESIZE - 1)
        self.addr_offset = addr - self.base_addr
        self.word_length = length
        self.no_of_bytes = self.word_length * self.word_size

        # align length to full words
        end_addr = addr + self.no_of_bytes
        if end_addr % self.mask:
            end_addr = (end_addr + self.word_size) & self.mask

        self.map_length = end_addr - self.base_addr
        self.fname = filename

        self.fd = os.open(self.fname, os.O_RDWR | os.O_SYNC)
        self.mem = mmap.mmap(self.fd, self.map_length, mmap.MAP_SHARED,
                             mmap.PROT_READ | mmap.PROT_WRITE,
                             offset=self.base_addr)

    def read(self):
        mem = self.mem
        virt_base_addr = self.addr_offset & self.mask
        mem.seek(virt_base_addr)

        data = []
        for i in range(self.no_of_bytes):
            data.append(struct.unpack('B', mem.read_byte())[0])

        abs_addr = self.base_addr + virt_base_addr
        return PydumpBuffer(abs_addr, data, self.word_size)

    def write(self, data):
        mem = self.mem
        virt_base_addr = self.addr_offset & self.mask
        mem.seek(virt_base_addr)

        if self.word_size == 1:
            mem.write(struct.pack('B', data))
        elif self.word_size == 2:
            mem.write(struct.pack('H', data))
        elif self.word_size == 4:
            mem.write(struct.pack('I', data))
        else:
            raise ValueError('Invalid word size')

    def write_bytes(self, bytes):
        if len(bytes) != self.no_of_bytes: raise ValueError('Wrong number of bytes given')
        mem = self.mem
        virt_base_addr = self.addr_offset & self.mask
        mem.seek(virt_base_addr)

        for byte in bytes:
            mem.write_byte(byte)
Run Code Online (Sandbox Code Playgroud)

示例运行(我用其他memdump工具[bin]准备内存为0xEEEEEEEE):

>>> from pydump import Pydump as memdump
>>> memdump(0x18007C20, 1, 4).read()
0xEEEEEEEE
>>> memdump(0x18007C20, 1, 4).write(0x12345678)
>>> memdump(0x18007C20, 1, 4).read()
0x00340078
>>> memdump(0x18007C20, 1, 4).write(0x87654321)
>>> memdump(0x18007C20, 1, 4).read()
0x00650021
Run Code Online (Sandbox Code Playgroud)

示例2(我无法在'第一个'字节处写入2个字节):

>>> memdump(0x18007C20, 1, 2).write(0xABCD)
>>> memdump(0x18007C20, 1, 4).read()
0x00650021
>>> memdump(0x18007C21, 1, 1).write(0xCD)
>>> memdump(0x18007C20, 1, 4).read()
0x00650021
>>> memdump(0x18007C22, 1, 1).write(0xCD)
>>> memdump(0x18007C20, 1, 4).read()
0x00CDCD00
Run Code Online (Sandbox Code Playgroud)

关于可能出现什么问题的任何想法?

k3t*_*hup 0

我现在知道出了什么问题了。答案是,这也是 python 的错误以及我的特定硬件/驱动程序的错误。

我查看了 mmap 的实现,它使用memcpy,正如我们所知,它逐字节复制。在 C 实现中,这种情况没有发生,当我们需要写入 4 个字节时,就写入了 4 个字节。所以这里出现了我的硬件/驱动程序的限制,即每个寄存器都必须完整写入(在陈述问题时我不知道这一点),因此当逐字节写入时我会得到奇怪的行为。

有些寄存器是16位的,有些是32位的。当我将 0xFFFF 写入 16 位寄存器时,我最终得到的是 0x00FF。所以 memcpy 复制了 0xFF 两次。我的驱动程序先写(0xFF),然后写(0xFF),所以我实际上在做的(因为python)是对字节0xFF的寄存器进行两次写入:)32位寄存器可能发生同样的情况,尽管它看起来不同(但也驾驶员的行为可能会有所不同)。

为了让它工作,我必须改变 python mmap 的实现:(