python mmap 写入时每隔一个字节跳过一次
python mmap skipping every second byte when writing
我在写入内存 (/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
当我尝试逐字节写入时,同样的情况发生了。
例如
write:
addr 0x200 0x43
addr 0x201 0x21
I get
addr 0x200 0x00
addr 0x201 0x21
代码:
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)
例子运行(我用其他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
示例 2(我无法在 'first' 字节位置写入 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
有什么问题吗?
我现在知道出了什么问题了。
答案是 python 和我的特定 hardware/driver.
一样都是错的
我查看了 mmap 的实现,它使用 memcpy,正如我们所知,它逐字节复制。在 C 实现中,这并没有发生,当我们需要写入 4 个字节时,就写入了 4 个字节。
所以这里出现了我的 hardware/driver 的限制,即每个寄存器都必须完整写入(在陈述问题时我不知道这一点),因此当逐字节写入时,我会得到奇怪的行为。
有的寄存器是16位的,有的是32位的。
当我将 0xFFFF 写入 16 位寄存器时,我最终得到了 0x00FF。所以 memcpy 复制了 0xFF 两次。我的驱动程序先写(0xFF)然后写(0xFF),所以我实际上在做什么(因为 python)是两次写入字节 0xFF 的寄存器:)
32 位寄存器可能也发生了同样的情况,尽管它看起来不同(但驱动程序的行为也可能不同)。
为了让它工作,我必须更改 python mmap 的实现:(
我在写入内存 (/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
当我尝试逐字节写入时,同样的情况发生了。 例如
write:
addr 0x200 0x43
addr 0x201 0x21
I get
addr 0x200 0x00
addr 0x201 0x21
代码:
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)
例子运行(我用其他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
示例 2(我无法在 'first' 字节位置写入 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
有什么问题吗?
我现在知道出了什么问题了。 答案是 python 和我的特定 hardware/driver.
一样都是错的我查看了 mmap 的实现,它使用 memcpy,正如我们所知,它逐字节复制。在 C 实现中,这并没有发生,当我们需要写入 4 个字节时,就写入了 4 个字节。 所以这里出现了我的 hardware/driver 的限制,即每个寄存器都必须完整写入(在陈述问题时我不知道这一点),因此当逐字节写入时,我会得到奇怪的行为。
有的寄存器是16位的,有的是32位的。 当我将 0xFFFF 写入 16 位寄存器时,我最终得到了 0x00FF。所以 memcpy 复制了 0xFF 两次。我的驱动程序先写(0xFF)然后写(0xFF),所以我实际上在做什么(因为 python)是两次写入字节 0xFF 的寄存器:) 32 位寄存器可能也发生了同样的情况,尽管它看起来不同(但驱动程序的行为也可能不同)。
为了让它工作,我必须更改 python mmap 的实现:(