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.
V10:
- refactor the variable of alignment.
ALIGNED_H means head aligned
ALIGNED_T means tail aligned
ALL_ALIGNED = ALIGNED_H | ALIGNED_T means means head and tail
all aligned
ALL_NOT_ALIGNED = ALIGNED_H & ALIGNED_T means head and tail
are all not aligned
v9:
- add class constants describe the alignment category
ALIGNED_H means head aligned
ALIGNED_T means tail aligned
ALIGNED_H | ALIGNED_T means head and tail all aligned
-ALIGNED_H | -ALIGNED_T means head and tail are all not aligned
v8:
- remove the pep8 warning.
v7:
- modify the python docstrings style.
- remove the cosmetic fixes.
v6:
- add all the commit message and the changes info
- modify error comments
- modify self.comments to self.comments = comments or [] to
void merging conflict
- refactor error message more verbose
- modify f.read() to the f.read().splitlines() to
void trailing '\n'
- remove pep8 warning
- refactor parse_ioport_tree to non-static method
- add the docstring to new introduced classes and functions
Signed-off-by: Xuguo Wang <
hudd...@gmail.com>
---
tools/jailhouse-config-create | 389 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 357 insertions(+), 32 deletions(-)
diff --git a/tools/jailhouse-config-create b/tools/jailhouse-config-create
index f0d65ed..5cb28a7 100755
--- a/tools/jailhouse-config-create
+++ b/tools/jailhouse-config-create
@@ -372,19 +372,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.
+
+ - args :
+ :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
+
+
+class IOMemRegion(IORegion):
+ """
+ Each IOMemRegion represents one of the /proc/iomem entries.
+ It extends IORegion by the comments property.
+
+ - args :
+ :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=''):
@@ -401,6 +444,72 @@ 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: ALIGNED_H region head aligned
+ :param arg2: ALIGNED_T region tail aligned
+ - args:
+ :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)
+ """
+
+ ALIGNED_T = 1
+ ALIGNED_H = 2
+ ALL_ALIGNED = ALIGNED_H | ALIGNED_T
+ ALL_NOT_ALIGNED = ALIGNED_H & ALIGNED_T
+
+ 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.
+
+ - return type :
+ int: the return value type.
+ - return value :
+ 0 means both head and tail are both not aligned
+ 1 means head not aligned but the tail is
+ 2 means tail not aligned but the head is
+ 3 means both are aligned
+ - example :
+ alignment = {$IOPortRegion}.alignment()
+ """
+ # region head bit and tail bit are both aligned
+ t = self.ALL_ALIGNED
+ # region head bit and tail bit are both not aligned
+ if self.start % 8 != 0 \
+ and (self.stop % 8 + 1) % 8 != 0:
+ t = self.ALL_NOT_ALIGNED
+ # region head bit is not aligned but tail do
+ elif self.start % 8 != 0 \
+ and (self.stop % 8 + 1) % 8 == 0:
+ t = self.ALIGNED_T
+ # region head bit is aligned but tail bit not
+ elif self.start % 8 == 0 \
+ and (self.stop % 8 + 1) % 8 != 0:
+ t = self.ALIGNED_H
+
+ return t
+
+
class IOAPIC:
def __init__(self, id, address, gsi_base, iommu=0, bdf=0):
self.id = id
@@ -417,7 +526,26 @@ class IOAPIC:
return (self.iommu << 16) | self.bdf
-class IOMemRegionTree:
+class IORegionTree:
+ """
+ Super class of IOMemRegionTree and IOPortRegionTree.
+
+ - args :
+ :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
@@ -435,6 +563,63 @@ 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.
+
+ - 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.
+
+ - args :
+ :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 ')]
@@ -458,32 +643,34 @@ 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.
+
+ - 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):
t.parent = lastnode
@@ -521,8 +708,22 @@ class IOMemRegionTree:
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.
+
+ - args :
+ :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:
@@ -559,6 +760,128 @@ 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.
+
+ - args:
+ :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.
+
+ - 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.
+
+ - args :
+ :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.
+
+ - args :
+ :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']
@@ -578,7 +901,7 @@ def parse_iomem(pcidevices):
regions = IOMemRegionTree.parse_iomem_tree(
IOMemRegionTree.parse_iomem_file())
- rom_region = MemRegion(0xc0000, 0xdffff, 'ROMs')
+ rom_region = IOMemRegion(0xc0000, 0xdffff, 'ROMs')
add_rom_region = False
ret = []
@@ -589,12 +912,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
@@ -668,11 +991,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
@@ -827,7 +1151,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)
@@ -1004,7 +1328,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 '
@@ -1136,9 +1461,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.1.4