123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- '''
- Stripped down version from https://github.com/vsergeev/python-periphery/blob/master/periphery/mmio.py
- '''
- import mmap
- import os
- import struct
- import sys
- # Alias long to int on Python 3
- if sys.version_info[0] >= 3:
- long = int
- class MMIOError(IOError):
- """Base class for MMIO errors."""
- pass
- class MMIO(object):
- def __init__(self, physaddr, size):
- """Instantiate an MMIO object and map the region of physical memory
- specified by the address base `physaddr` and size `size` in bytes.
- Args:
- physaddr (int, long): base physical address of memory region.
- size (int, long): size of memory region.
- Returns:
- MMIO: MMIO object.
- Raises:
- MMIOError: if an I/O or OS error occurs.
- TypeError: if `physaddr` or `size` types are invalid.
- """
- self.mapping = None
- self._open(physaddr, size)
- def __del__(self):
- self.close()
- def __enter__(self):
- pass
- def __exit__(self, t, value, traceback):
- self.close()
- def _open(self, physaddr, size):
- if not isinstance(physaddr, (int, long)):
- raise TypeError("Invalid physaddr type, should be integer.")
- if not isinstance(size, (int, long)):
- raise TypeError("Invalid size type, should be integer.")
- pagesize = os.sysconf(os.sysconf_names['SC_PAGESIZE'])
- self._physaddr = physaddr
- self._size = size
- self._aligned_physaddr = physaddr - (physaddr % pagesize)
- self._aligned_size = size + (physaddr - self._aligned_physaddr)
- try:
- fd = os.open("/dev/mem", os.O_RDWR | os.O_SYNC)
- except OSError as e:
- raise MMIOError(e.errno, "Opening /dev/mem: " + e.strerror)
- try:
- self.mapping = mmap.mmap(
- fd, self._aligned_size, flags=mmap.MAP_SHARED, prot=mmap.PROT_WRITE, offset=self._aligned_physaddr)
- except OSError as e:
- raise MMIOError(e.errno, "Mapping /dev/mem: " + e.strerror)
- try:
- os.close(fd)
- except OSError as e:
- raise MMIOError(e.errno, "Closing /dev/mem: " + e.strerror)
- # Methods
- def _adjust_offset(self, offset):
- return offset + (self._physaddr - self._aligned_physaddr)
- def _validate_offset(self, offset, length):
- if (offset + length) > self._aligned_size:
- raise ValueError("Offset out of bounds.")
- def read32(self, offset):
- """Read 32-bits from the specified `offset` in bytes, relative to the
- base physical address of the MMIO region.
- Args:
- offset (int, long): offset from base physical address, in bytes.
- Returns:
- int: 32-bit value read.
- Raises:
- TypeError: if `offset` type is invalid.
- ValueError: if `offset` is out of bounds.
- """
- if not isinstance(offset, (int, long)):
- raise TypeError("Invalid offset type, should be integer.")
- offset = self._adjust_offset(offset)
- self._validate_offset(offset, 4)
- return struct.unpack("=L", self.mapping[offset:offset + 4])[0]
- def write32(self, offset, value):
- """Write 32-bits to the specified `offset` in bytes, relative to the
- base physical address of the MMIO region.
- Args:
- offset (int, long): offset from base physical address, in bytes.
- value (int, long): 32-bit value to write.
- Raises:
- TypeError: if `offset` or `value` type are invalid.
- ValueError: if `offset` or `value` are out of bounds.
- """
- if not isinstance(offset, (int, long)):
- raise TypeError("Invalid offset type, should be integer.")
- if not isinstance(value, (int, long)):
- raise TypeError("Invalid value type, should be integer.")
- if value < 0 or value > 0xffffffff:
- raise ValueError("Value out of bounds.")
- offset = self._adjust_offset(offset)
- self._validate_offset(offset, 4)
- self.mapping[offset:offset + 4] = struct.pack("=L", value)
- def close(self):
- """Unmap the MMIO object's mapped physical memory."""
- if self.mapping is None:
- return
- self.mapping.close()
- self.mapping = None
- self._fd = None
- # String representation
- def __str__(self):
- return "MMIO 0x%08x (size=%d)" % (self.base, self.size)
|