Files
seL4/tools/hardware/memory.py
Axel Heider e75d22bedd python: align imports
Signed-off-by: Axel Heider <axelheider@gmx.de>
2021-11-14 11:44:00 +11:00

116 lines
4.3 KiB
Python

#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: GPL-2.0-only
#
import functools
import hardware
@functools.total_ordering
class Region:
''' Represents a region of memory. '''
def __init__(self, base: int, size: int, owner: 'WrappedNode' = None):
self.base = base
self.size = size
self.owner = owner
@staticmethod
def clone(other):
return Region(other.base, other.size)
def __repr__(self):
''' Returns a string representation that is a valid Python expression
that eval() can parse. '''
return 'Region(base=0x{:x},size=0x{:x})'.format(self.base, self.size)
def __str__(self):
''' Returns a string representation. '''
return 'Region [0x{:x}..0x{:x}] ({:d} bytes)'.format(
self.base,
self.base + self.size - (1 if self.size > 0 else 0),
self.size)
def __eq__(self, other):
return self.base == other.base and self.size == other.size
def __ne__(self, other):
# Needed only for py2.
return not self.__eq__(other)
def __gt__(self, other):
return self.base > other.base
def __hash__(self):
return hash((self.base, self.size))
@staticmethod
def from_range(start, end, owner=None):
''' create a region from a start/end rather than start/size '''
if start > end:
raise ValueError(
'invalid rage start (0x{:x}) > end (0x{:x})'.format(start > end))
return Region(start, end - start, owner)
def overlaps(self, other):
''' returns True if this region overlaps the given region '''
# Either our base is first, and to overlap our end must be > other.base
# or other.base is first, and to overlap other's end must be > self.base
return (self.base <= other.base and (self.base + self.size) > other.base) \
or (other.base <= self.base and (other.base + other.size) > self.base)
def reserve(self, excluded):
''' returns an array of regions that represent this region
minus the excluded range '''
if not self.overlaps(excluded):
return [Region(self.base, self.size, self.owner)]
ret = []
if self.base < excluded.base:
# the first region is from our base to excluded.base
ret.append(Region.from_range(self.base, excluded.base, self.owner))
# skip the region from excluded.base - excluded.base + excluded.size
# if there's anything left, add it.
if (excluded.base + excluded.size) < (self.base + self.size):
ret.append(Region.from_range(excluded.base + excluded.size,
self.base + self.size, self.owner))
else: # self.base >= excluded.base
# we skip the first chunk
# we add what's left after the current chunk.
if (self.base + self.size) > (excluded.base + excluded.size):
ret.append(Region.from_range(excluded.base + excluded.size,
self.base + self.size, self.owner))
return ret
def align_base(self, align_bits):
''' align this region up to a given number of bits '''
new_base = hardware.utils.align_up(self.base, align_bits)
diff = new_base - self.base
if self.size < diff:
raise ValueError(
'can''t align region base to {} bits, {} too small'.format(
align_bits, self))
# This could become an empty region now. We don't care, the caller has
# to check if this region still fits its needs.
return Region(new_base, self.size - diff, self.owner)
def align_size(self, align_bits):
''' align this region's size to a given number of bits.
will move the base address down and the region's size
up '''
new_base = hardware.utils.align_down(self.base, align_bits)
new_size = hardware.utils.align_up(self.size, align_bits)
return Region(new_base, new_size, self.owner)
def make_chunks(self, chunksz):
base = self.base
size = self.size
ret = []
while size > 0:
ret.append(Region(base, min(size, chunksz), self.owner))
base += chunksz
size -= chunksz
return ret