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.
