Abstract the common property of the ioports from the
/proc/ioports as the super class named IOPortRegion,
using the region of ioports from the IOPortRegionTree,
this tree includes all of the ioport regions we could
use this regions generate the pio_bitmap.

v6:
- add all the commit messages and the changes info
- modify error comments
- modify self.comments to self.comments = comments or [] to avoid merging 
conflict
- refactor error message more verbose
- modify f.read() to the f.read().splitlines() to void trailing '\n'
- remove pep8 warnings
- refactor parse_ioport_tree to non-static method
- add the docstring to new introduced classes and functions

Signed-off-by: Xuguo Wang <[email protected]>
---
 tools/jailhouse-config-create | 421 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 374 insertions(+), 47 deletions(-)

diff --git a/tools/jailhouse-config-create b/tools/jailhouse-config-create
index 4e61abc..dfe98db 100755
--- a/tools/jailhouse-config-create
+++ b/tools/jailhouse-config-create
@@ -368,22 +368,62 @@ class PCIPCIBridge(PCIDevice):
         return (secondbus, subordinate)
 
 
-class MemRegion:
-    def __init__(self, start, stop, typestr, comments=None):
+class IORegion:
+    """
+    The super class of the IOPortRegion and IOMemRegion.
+
+    The IORegion means a region of a /proc/io{mem,ports} entry,
+    which starts from param start, ends of the param stop.
+
+    - ** attributes **:
+        :param arg1: start      start address
+        :param arg2: stop       stop address
+        :param arg3: typestr    region type description
+    - ** type **:
+        :type arg1: long
+        :type arg2: long
+        :type arg3: str
+    - ** example **:
+        /proc/ioports:
+            region = IORegion(0x0, 0x1f, "dma1")
+        /proc/iomem:
+            region = IORegion(0x0000, 0xfff, "reserved")
+    """
+
+    def __init__(self, start, stop, typestr):
         self.start = start
         self.stop = stop
         self.typestr = typestr
-        if comments is None:
-            self.comments = []
-        else:
-            self.comments = comments
+
+
+class IOMemRegion(IORegion):
+    """
+    Each IOMemRegion represents one of the /proc/iomem entries.
+    It extends IORegion by the comments property.
+
+    - ** attributes **:
+        :param arg1: start      region start address
+        :param arg2: stop       region stop address
+        :param arg3: typestr    region type description
+        :param arg4: comments   region specified description
+    - ** type **:
+        :type arg1: long
+        :type arg2: long
+        :type arg3: str
+        :type arg4: str
+    - ** example **:
+        memregion = IOMemRegion(0x0000, 0xfff, "reserved", NULL)
+    """
+
+    def __init__(self, start, stop, typestr, comments=None):
+        self.comments = comments or []
+        IORegion.__init__(self, start, stop, typestr)
 
     def __str__(self):
-        return 'MemRegion: %08x-%08x : %s' % \
+        return 'IOMemRegion: %08x-%08x : %s' % \
             (self.start, self.stop, self.typestr)
 
     def size(self):
-        # round up to full PAGE_SIZE
         return int((self.stop - self.start + 0xfff) / 0x1000) * 0x1000
 
     def flagstr(self, p=''):
@@ -400,6 +440,68 @@ class MemRegion:
         return 'JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE'
 
 
+class IOPortRegion(IORegion):
+    """
+    Each IOPortRegion represents one of the /proc/ioports entries.
+    The value == 0 means permit, 1 means intercept.
+
+    - ** attributes **:
+        :param arg1: start      region start address
+        :param arg2: stop       region stop address
+        :param arg3: typestr    region type description
+        :param arg4: value      region value description
+    - ** type **:
+        :type arg1: long
+        :type arg2: long
+        :type arg3: str
+        :type arg4: int
+    - ** example **:
+        portRegion = IOPortRegion(0x0, 0x1f, "dma1", -0x1)
+    """
+
+    def __init__(self, start, stop, typestr, value=0):
+        self.value = value
+        IORegion.__init__(self, start, stop, typestr)
+
+    def size(self):
+        return self.stop - self.start + 1
+
+    def alignment(self):
+        """
+        Return the region alignment.
+
+        - ** parameters **:
+            no.
+        - ** type **:
+            no.
+        - ** return type **:
+            int: the return value type.
+        - ** return value **:
+            0 means both are aligned
+            1 means both head and tail are both not aligned
+            2 means head not aligned but the tail is
+            3 means tail not aligned but the head is
+        - ** example **:
+            alignment = {$IOPortRegion}.alignment()
+        """
+        # region head bit and tail bit are both aligned
+        t = 0
+        # region head bit and tail bit are both not aligned
+        if self.start % 8 != 0 \
+                and (self.stop % 8 + 1) % 8 != 0:
+            t = 1
+        # region head bit is not aligned but tail do
+        elif self.start % 8 != 0 \
+                and (self.stop % 8 + 1) % 8 == 0:
+            t = 2
+        # region head bit is aligned but tail bit not
+        elif self.start % 8 == 0 \
+                and (self.stop % 8 + 1) % 8 != 0:
+            t = 3
+
+        return t
+
+
 class IOAPIC:
     def __init__(self, id, address, gsi_base, iommu=0, bdf=0):
         self.id = id
@@ -416,7 +518,26 @@ class IOAPIC:
         return (self.iommu << 16) | self.bdf
 
 
-class IOMemRegionTree:
+class IORegionTree:
+    """
+    Super class of IOMemRegionTree and IOPortRegionTree.
+
+    - ** attributes **:
+        :param arg1: region     region of a /proc/io{mem, ports} entry
+        :param arg2: level      the level of region
+    - ** type **:
+        :type arg1: IO{Port, Mem}Region
+        :type arg2: int
+    - ** example **:
+        level, r = IOMemRegionTree.parse_line(IOMemRegion, line)
+        or
+        level, r = IOPortRegionTree.parse_line(IOPortRegion, line)
+    """
+
+    # This regex matches entries in /proc/ioports or /proc/iomem, like
+    # '  0020-0021 : pic1'
+    IOEntry_Regex = re.compile('( *)([0-9a-f]*)-([0-9a-f]*) : (\w?.*)')
+
     def __init__(self, region, level):
         self.region = region
         self.level = level
@@ -434,6 +555,65 @@ class IOMemRegionTree:
             s += str(c)
         return s
 
+    @staticmethod
+    def parse_line(RegionClass, line):
+        """
+        Parse an entry of /proc/iomem or /proc/ioports to an object
+        of region, this region type is specified by the regionclass.
+
+        The parse regex is "( *)([0-9a-f]*)-([0-9a-f]*) : (\w?.*)".
+
+        - ** parameters **:
+            :param arg1: regionclass    region type
+            :param arg2: line           an entry of /proc/iomem or
+                                        /proc/ioports content
+        - ** type **:
+            :type arg1: IO{Port, Mem}Region
+            :type arg2: str
+        - ** return type **:
+            list: a list node contains tree node level and the region of entry
+        - ** return value **:
+            list = [level, region]
+        - ** example **:
+            level, r = IOMemRegionTree.parse_line(IOMemRegion, line)
+            or
+            level, r = IOPortRegionTree.parse_line(IOPortRegion, line)
+        """
+        match = IORegionTree.IOEntry_Regex.match(line)
+        if not match:
+            raise ValueError('invalid entry: %s' % line)
+
+        # blank level
+        level = int(match.group(1).count(' ') / 2) + 1
+        # start address
+        start = match.group(2)
+        # end address
+        stop = match.group(3)
+        # comments
+        typestr = match.group(4)
+        return level, RegionClass(int(start, 16), int(stop, 16), typestr)
+
+
+class IOMemRegionTree(IORegionTree):
+    """
+    This class parses the /proc/iomem file to the tree structure and parse the
+    tree structure to a list contains all regions.
+
+    - ** attributes **:
+        :param arg1: region     region of a /proc/iomem entry
+        :param arg2: level      the level of region
+    - ** type **:
+        :type arg1: IOMemRegion
+        :type arg2: int
+    - ** example **:
+        level, r = IOMemRegionTree.parse_line(IOMemRegion, line)
+        or
+        level, r = IOPortRegionTree.parse_line(IOPortRegion, line)
+    """
+
+    def __init__(self, region, level):
+        IORegionTree.__init__(self, region, level)
+
     def regions_split_by_kernel(self):
         kernel = [x for x in self.children if
                   x.region.typestr.startswith('Kernel ')]
@@ -457,38 +637,44 @@ class IOMemRegionTree:
 
         # before Kernel if any
         if (r.start < kernel_start):
-            before_kernel = MemRegion(r.start, kernel_start - 1, s)
+            before_kernel = IOMemRegion(r.start, kernel_start - 1, s)
 
-        kernel_region = MemRegion(kernel_start, kernel_stop, "Kernel")
+        kernel_region = IOMemRegion(kernel_start, kernel_stop, "Kernel")
 
         # after Kernel if any
         if (r.stop > kernel_stop):
-            after_kernel = MemRegion(kernel_stop + 1, r.stop, s)
+            after_kernel = IOMemRegion(kernel_stop + 1, r.stop, s)
 
         return [before_kernel, kernel_region, after_kernel]
 
     @staticmethod
-    def parse_iomem_line(line):
-        a = line.split(':', 1)
-        level = int(a[0].count(' ') / 2) + 1
-        region = a[0].split('-', 1)
-        a[1] = a[1].strip()
-        return level, MemRegion(int(region[0], 16), int(region[1], 16), a[1])
-
-    @staticmethod
     def parse_iomem_file():
+        """
+        This function parses the file of /proc/iomem to a tree structure.
+
+        - ** parameters **:
+            no.
+        - ** type **:
+            no.
+        - ** return type **:
+            IOMemRegionTree: /proc/iomem all entries' tree root node.
+        - ** return value **:
+            Return the tree root node.
+        - ** example **:
+            regions = IOMemRegionTree.parse_iomem_file().parse_iomem_tree()
+        """
         root = IOMemRegionTree(None, 0)
         f = input_open('/proc/iomem')
         lastlevel = 0
         lastnode = root
-        for line in f:
-            (level, r) = IOMemRegionTree.parse_iomem_line(line)
+        for line in f.read().splitlines():
+            level, r = IOMemRegionTree.parse_line(IOMemRegion, line)
             t = IOMemRegionTree(r, level)
-            if (t.level > lastlevel):
+            if t.level > lastlevel:
                 t.parent = lastnode
-            if (t.level == lastlevel):
+            if t.level == lastlevel:
                 t.parent = lastnode.parent
-            if (t.level < lastlevel):
+            if t.level < lastlevel:
                 p = lastnode.parent
                 while(t.level < p.level):
                     p = p.parent
@@ -510,18 +696,32 @@ class IOMemRegionTree:
             r = tree.region
             s = r.typestr
 
-            if (s.find('HPET') >= 0):
+            if s.find('HPET') >= 0:
                 regions.append(r)
 
             # if the tree continues recurse further down ...
-            if (len(tree.children) > 0):
+            if len(tree.children) > 0:
                 regions.extend(IOMemRegionTree.find_hpet_regions(tree))
 
         return regions
 
     # recurse down the tree
-    @staticmethod
     def parse_iomem_tree(tree):
+        """
+        This function parses the IOMemRegionTree tree nodes to regions,
+        and return the list contains all regions.
+
+        - ** parameters **:
+            :param arg1: tree           IOMemRegionTree tree root node
+        - ** type **:
+            :type arg1: IOMemRegionTree
+        - ** return type **:
+            list: contains all /proc/iomem tree nodes.
+        - ** return value **:
+            Return the list regions of /proc/iomem.
+        - ** example **:
+            regions = IOMemRegionTree.parse_iomem_file().parse_iomem_tree()
+        """
         regions = []
 
         for tree in tree.children:
@@ -543,13 +743,13 @@ class IOMemRegionTree:
                 continue
 
             # generally blacklisted, unless we find an HPET behind it
-            if (s == 'reserved'):
+            if s == 'reserved':
                 regions.extend(IOMemRegionTree.find_hpet_regions(tree))
                 continue
 
             # if the tree continues recurse further down ...
-            if (len(tree.children) > 0):
-                regions.extend(IOMemRegionTree.parse_iomem_tree(tree))
+            if len(tree.children) > 0:
+                regions.extend(tree.parse_iomem_tree())
                 continue
 
             # add all remaining leaves
@@ -558,6 +758,132 @@ class IOMemRegionTree:
         return regions
 
 
+class IOPortRegionTree(IORegionTree):
+    """
+    This class parses the /proc/ioports file to the tree structure and parse
+    the tree structure to a list contains all regions.
+
+    - ** attributes **:
+        :param arg1: region     region of a /proc/ioports entry
+        :param arg2: level      the level of region tree node
+    - ** type **:
+        :type arg1: IOPortRegion
+        :type arg2: int
+    - ** example **:
+        level, r = IOMemRegionTree.parse_line(IOMemRegion, line)
+        or
+        level, r = IOPortRegionTree.parse_line(IOPortRegion, line)
+    """
+
+    def __init__(self, region, level):
+        IORegionTree.__init__(self, region, level)
+
+    @staticmethod
+    def parse_ioport_file():
+        """
+        This function parses the file of /proc/ioports to a tree structure.
+
+        - ** parameters **:
+            no.
+        - ** type **:
+            no.
+        - ** return type **:
+            IOPortRegionTree: contains /proc/ioports tree structure.
+        - ** return value **:
+            Return the tree root node.
+        - ** example **:
+            regions = IOPortRegionTree.parse_ioport_file().parse_ioport_tree()
+        """
+        root = IOPortRegionTree(None, 0)
+        f = input_open('/proc/ioports')
+        lastlevel = 0
+        lastnode = root
+        for line in f.read().splitlines():
+            level, r = IOPortRegionTree.parse_line(IOPortRegion, line)
+            t = IOPortRegionTree(r, level)
+            if t.level > lastlevel:
+                t.parent = lastnode
+            if t.level == lastlevel:
+                t.parent = lastnode.parent
+            if t.level < lastlevel:
+                p = lastnode.parent
+                while(t.level < p.level):
+                    p = p.parent
+                t.parent = p.parent
+
+            t.parent.children.append(t)
+            lastnode = t
+            lastlevel = t.level
+        f.close()
+
+        return root
+
+    # recurse down the tree
+    def parse_ioport_tree(tree):
+        """
+        This function parses the IOPortRegionTree tree nodes to regions,
+        and return the list contains all regions.
+
+        - ** parameters **:
+            :param arg1: tree           IOPortRegionTree tree root node
+        - ** type **:
+            :type arg1: IOPortRegionTree
+        - ** return type **:
+            list: contains all /proc/ioports tree nodes.
+        - ** return value **:
+            Return the list regions of /proc/ioports.
+        - ** example **:
+            regions = IOPortRegionTree.parse_ioport_file().parse_ioport_tree()
+        """
+        regions = []
+
+        for tree in tree.children:
+            r = tree.region
+            c = r.typestr
+
+            # intercept keyboard and PCI conf1
+            if c is not None and (c == 'keyboard' or c == 'PCI conf1'):
+                r.value = IOPortRegionTree.get_first_ioport_byte(
+                    r.start, r.stop)
+
+            # if the tree continues recurse further down ...
+            if len(tree.children) > 0:
+                regions.extend(tree.parse_ioport_tree())
+                continue
+
+            # add all remaining leaves
+            regions.append(r)
+
+        return regions
+
+    @staticmethod
+    def get_first_ioport_byte(start_permitted, last_permitted):
+        """
+        Get a byte of ioport region mask from start_permitted, end
+        at the last_permitted bit.
+
+        - ** parameters **:
+            :param arg1: start_permitted    first permitted bit
+            :param arg2: last_permitted     last permitted bit
+        - ** type **:
+            :type arg1: int
+            :type arg2: int
+        - ** return type **:
+            int:
+        - ** return value **:
+            a bitwise mask start from start_permitted to last_permitted
+        - ** example **:
+            value_head = IOPortRegionTree.get_first_ioport_byte(
+                                        region.start, region.stop)
+        """
+        byte_head = start_permitted % 8
+        byte_tail = last_permitted % 8
+        byte = (1 << byte_head) - 1
+        byte |= (~((1 << (byte_tail + 1)) - 1) & 0xff)
+        byte &= 0xff
+        return int(byte)
+
+
 class IOMMUConfig(object):
     def __init__(self, props):
         self.base_addr = props['base_addr']
@@ -574,10 +900,9 @@ class IOMMUConfig(object):
 
 
 def parse_iomem(pcidevices):
-    regions = IOMemRegionTree.parse_iomem_tree(
-        IOMemRegionTree.parse_iomem_file())
+    regions = IOMemRegionTree.parse_iomem_file().parse_iomem_tree()
 
-    rom_region = MemRegion(0xc0000, 0xdffff, 'ROMs')
+    rom_region = IOMemRegion(0xc0000, 0xdffff, 'ROMs')
     add_rom_region = False
 
     ret = []
@@ -588,12 +913,12 @@ def parse_iomem(pcidevices):
         for d in pcidevices:
             if d.msix_address >= r.start and d.msix_address <= r.stop:
                 if d.msix_address > r.start:
-                    head_r = MemRegion(r.start, d.msix_address - 1,
-                                       r.typestr, r.comments)
+                    head_r = IOMemRegion(r.start, d.msix_address - 1,
+                                         r.typestr, r.comments)
                     ret.append(head_r)
                 if d.msix_address + d.msix_region_size < r.stop:
-                    tail_r = MemRegion(d.msix_address + d.msix_region_size,
-                                       r.stop, r.typestr, r.comments)
+                    tail_r = IOMemRegion(d.msix_address + d.msix_region_size,
+                                         r.stop, r.typestr, r.comments)
                     ret.append(tail_r)
                 append_r = False
                 break
@@ -667,11 +992,12 @@ def alloc_mem(regions, size):
             r.stop + 1 >= mem[0] + mem[1]
         ):
             if r.start < mem[0]:
-                head_r = MemRegion(r.start, mem[0] - 1, r.typestr, r.comments)
+                head_r = IOMemRegion(r.start, mem[0] - 1,
+                                     r.typestr, r.comments)
                 regions.insert(regions.index(r), head_r)
             if r.stop + 1 > mem[0] + mem[1]:
-                tail_r = MemRegion(mem[0] + mem[1], r.stop, r.typestr,
-                                   r.comments)
+                tail_r = IOMemRegion(mem[0] + mem[1], r.stop,
+                                     r.typestr, r.comments)
                 regions.insert(regions.index(r), tail_r)
             regions.remove(r)
             return mem
@@ -826,7 +1152,7 @@ def parse_dmar(pcidevices, ioapics, dmar_regions):
                     comments.append('DMAR parser could not decode device path')
                 offset += scope_len
 
-            reg = MemRegion(base, limit, 'ACPI DMAR RMRR', comments)
+            reg = IOMemRegion(base, limit, 'ACPI DMAR RMRR', comments)
             regions.append(reg)
 
         f.seek(struct_len - offset, os.SEEK_CUR)
@@ -1003,7 +1329,8 @@ def parse_ivrs(pcidevices, ioapics):
                       'regions. The memory at 0x%x will be mapped accessible '
                       'to all devices.' % mem_addr)
 
-            regions.append(MemRegion(mem_addr, mem_len, 'ACPI IVRS', comment))
+            regions.append(IOMemRegion(mem_addr, mem_len,
+                                       'ACPI IVRS', comment))
         elif type == 0x40:
             raise RuntimeError(
                 'You board uses IVRS Rev. 2 feature Jailhouse doesn\'t '
@@ -1064,7 +1391,7 @@ def get_cpu_vendor():
     if cpuvendor is not None:
         return cpuvendor
     with input_open('/proc/cpuinfo', 'r') as f:
-        for line in f:
+        for line in f.read().splitlines():
             if not line.strip():
                 continue
             key, value = line.split(':')
@@ -1135,9 +1462,9 @@ elif (total > ourmem[1]):
 
 hvmem[0] = ourmem[0]
 
-inmatereg = MemRegion(ourmem[0] + hvmem[1],
-                      ourmem[0] + hvmem[1] + inmatemem - 1,
-                      'JAILHOUSE Inmate Memory')
+inmatereg = IOMemRegion(ourmem[0] + hvmem[1],
+                        ourmem[0] + hvmem[1] + inmatemem - 1,
+                        'JAILHOUSE Inmate Memory')
 regions.append(inmatereg)
 
 cpucount = count_cpus()
-- 
2.5.0

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to