Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-07-12 Thread Jan Kiszka
On 12.07.19 17:59, Ralf Ramsauer wrote:
> Hi,
>
> On 6/21/19 12:06 AM, Andrej Utz wrote:
>> This replaces the old static port list with actual port regions from
>> '/proc/ioports'. The static regions from said list are kept and override
>> the data in case of region overlap to retain compability.
>> The generated port list is virtually identicall to the old one but eases
>> manual configuration.
>
> just found a bug in this series. This series creates regions such as:
>
> 
> [  0x80/8 ...   0x87/8] =   -1, /* 0080-0087 : dma page reg */
> [  0x88/8 ...   0x8f/8] =   -1, /* 0088-008f : dma page reg */
> [  0xa0/8 ...   0xa7/8] =   -1, /* 00a0-00a1 : pic2 */
> 
>
> Now we have a hole between [0x90/8 ... 0x1f/8]. A hole means that this
> area will be initialised with zero -> access is permitted.
>
> Root of this bug: In addition known port regions, we must also respect
> unknown port regions and deny access.
>
> @Jan: This brings me to an idea. The TODO says that whitelist-based MSR
> bitmaps are a v1.0 target. I think the PIO bitmap would also benefit if
> it would be whitelist based. Do you agree?

Sure, that is what we tried so far, but not for PCI. And then there is always
the trade-off between locking down the system and running directly into a
violation on first start.

>
> E.g.:
> .pio_bitmap = {
>   [ 0x3f8/8 ... 0x3ff/8 ] = -1,
> },
>
> would denote that only access to 3f8-3ff is allowed. All other ports are
> denied. Much easier to write and understand.

The bitmap is encoded in machine format. Both Intel and AMD use the inverse
form, don't ask me why.

Of course, inversion in software would be feasible and hopefully limited to
vcpu_cell_init/exit(). Hmm, no, also i8042_access_handler(). The bigger issue
might be the transformation of existing configs.

Jan

-- 
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 jailhouse-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/97013af8-fec9-f42b-6c40-9712fff0c266%40web.de.
For more options, visit https://groups.google.com/d/optout.


Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-07-12 Thread Andrej Utz

Hi all,

On 12.07.19 17:59, Ralf Ramsauer wrote:

Hi,

On 6/21/19 12:06 AM, Andrej Utz wrote:

This replaces the old static port list with actual port regions from
'/proc/ioports'. The static regions from said list are kept and override
the data in case of region overlap to retain compability.
The generated port list is virtually identicall to the old one but eases
manual configuration.


just found a bug in this series. This series creates regions such as:


[  0x80/8 ...   0x87/8] =   -1, /* 0080-0087 : dma page reg */
[  0x88/8 ...   0x8f/8] =   -1, /* 0088-008f : dma page reg */
[  0xa0/8 ...   0xa7/8] =   -1, /* 00a0-00a1 : pic2 */


Now we have a hole between [0x90/8 ... 0x1f/8]. A hole means that this
area will be initialised with zero -> access is permitted.


Ack, this is not intended.


Root of this bug: In addition known port regions, we must also respect
unknown port regions and deny access.

@Jan: This brings me to an idea. The TODO says that whitelist-based MSR
bitmaps are a v1.0 target. I think the PIO bitmap would also benefit if
it would be whitelist based. Do you agree?

E.g.:
.pio_bitmap = {
[ 0x3f8/8 ... 0x3ff/8 ] = -1,
},

would denote that only access to 3f8-3ff is allowed. All other ports are
denied. Much easier to write and understand.

   Ralf


Unless there is some bit trickery optimization, I would also prefer "0 = 
disallowed".


Also including Hennings concerns:
>The main issue really is that a lot of device drivers do not register
>themselfs as port-users, so we can not detect them.
>But those exotic ports are probably blocked in the default config so
>there is no new problem.

I will reconsider my approach how to generate ioports list. Parsing PCI 
config space seems like a better source instead of /proc/ioports. 
Depending how secretive PCI devices are with their I/O specs, 
refactoring MemRegion generation may also be necessary to use the same 
logic. Need to investigate further.


But for now thanks for reviewing. Consider this patch queue retracted.

Andrej Utz



--
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 jailhouse-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/011d894f-8cc0-1603-0c72-df3aedff943c%40st.oth-regensburg.de.
For more options, visit https://groups.google.com/d/optout.


Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-07-12 Thread Ralf Ramsauer
Hi,

On 6/21/19 12:06 AM, Andrej Utz wrote:
> This replaces the old static port list with actual port regions from
> '/proc/ioports'. The static regions from said list are kept and override
> the data in case of region overlap to retain compability.
> The generated port list is virtually identicall to the old one but eases
> manual configuration.

just found a bug in this series. This series creates regions such as:


[  0x80/8 ...   0x87/8] =   -1, /* 0080-0087 : dma page reg */
[  0x88/8 ...   0x8f/8] =   -1, /* 0088-008f : dma page reg */
[  0xa0/8 ...   0xa7/8] =   -1, /* 00a0-00a1 : pic2 */


Now we have a hole between [0x90/8 ... 0x1f/8]. A hole means that this
area will be initialised with zero -> access is permitted.

Root of this bug: In addition known port regions, we must also respect
unknown port regions and deny access.

@Jan: This brings me to an idea. The TODO says that whitelist-based MSR
bitmaps are a v1.0 target. I think the PIO bitmap would also benefit if
it would be whitelist based. Do you agree?

E.g.:
.pio_bitmap = {
[ 0x3f8/8 ... 0x3ff/8 ] = -1,
},

would denote that only access to 3f8-3ff is allowed. All other ports are
denied. Much easier to write and understand.

  Ralf


> 
> Signed-off-by: Andrej Utz 
> ---
>  pyjailhouse/sysfs_parser.py   | 150 ++
>  tools/jailhouse-config-create |  26 ++
>  tools/root-cell-config.c.tmpl |  31 ---
>  3 files changed, 176 insertions(+), 31 deletions(-)
> 
> diff --git a/pyjailhouse/sysfs_parser.py b/pyjailhouse/sysfs_parser.py
> index d612c6d3..ce490236 100644
> --- a/pyjailhouse/sysfs_parser.py
> +++ b/pyjailhouse/sysfs_parser.py
> @@ -141,6 +141,52 @@ def parse_iomem(pcidevices):
>  
>  return ret, dmar_regions
>  
> +def parse_ioports():
> +regions = IOMapTree.parse_ioports_tree(
> +IOMapTree.parse_iomap_file('/proc/ioports', PortRegion))
> +
> +tmp = [
> +# static regions
> +PortRegion(0x0, 0x3f, ''),
> +PortRegion(0x40, 0x43, 'PIT', allowed=True),
> +PortRegion(0x60, 0x61, 'NMI', allowed=True, comments=["HACK!"]), # 
> NMI status/control
> +PortRegion(0x64, 0x64, 'NMI', allowed=True, comments=["HACK!"]), # 
> ditto
> +PortRegion(0x70, 0x71, 'RTC', allowed=True),
> +PortRegion(0x3b0, 0x3df, 'VGA', allowed=True),
> +PortRegion(0xd00, 0x, 'PCI bus', allowed=True),
> +]
> +
> +pm_timer_base = None
> +for r in regions:
> +if r.typestr == 'ACPI PM_TMR':
> +pm_timer_base = r.start
> +
> +tmp.append(r)
> +
> +tmp.sort(key=lambda r: r.start)
> +ret = [ tmp[0] ]
> +
> +# adjust overlapping regions
> +for r in tmp[1:]:
> +prev = ret[-1]
> +
> +# combine multiple regions under the same bit mask
> +if prev.aligned_stop() >= r.aligned_start():
> +if r.stop > prev.stop:
> +n = prev
> +while n.neighbor != None:
> +n = n.neighbor
> +n.neighbor = r
> +continue
> +
> +# forbid access to unrecognized regions
> +if prev.aligned_stop() - r.aligned_start() > 0:
> +ret.append(
> +PortRegion(prev.aligned_stop() + 1, r.aligned_start() - 1, 
> ''))
> +
> +ret.append(r)
> +
> +return (ret, pm_timer_base)
>  
>  def parse_pcidevices():
>  int_src_cnt = 0
> @@ -772,6 +818,85 @@ class MemRegion:
>  return 'JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE'
>  
>  
> +class PortRegion:
> +def __init__(self, start, stop, typestr, comments=None, allowed=False):
> +self.start = start
> +self.stop = stop
> +self.typestr = typestr or ''
> +self.comments = comments or []
> +self.allowed = allowed
> +self.neighbor = None
> +
> +def __str__(self):
> +# as in MemRegion this method is purely for C comment generation
> +
> +# remove consecutive duplicates
> +neighbor = self.neighbor
> +stop = self.stop
> +ns = ''
> +while neighbor:
> +if self.typestr != neighbor.typestr \
> +or self.comments != neighbor.comments:
> +ns += ', ' + str(neighbor)
> +break
> +
> +stop = neighbor.stop
> +neighbor = neighbor.neighbor
> +
> +s = ''
> +# pretty print single ports
> +if self.start == stop:
> +s += '%5s' % ''
> +else:
> +s += '%04x-' % self.start
> +
> +s += '%04x' % stop
> +
> +
> +if self.typestr:
> +s += ' : ' + self.typestr
> +
> +if self.comments:
> +s += ' (' + ', '.join(c for c in self.comments) + ')'
> +
> +s += ns
> +return s
> +
> +# used in root-cell-config.c.tmpl
> +def is_combined(self):
> +neighbor = self.neighbor
> +while neighbor:
> +if self.typestr != neighbor.typestr:
> +  

Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-06-30 Thread Andrej Utz
Hello Henning,

On 28/06/2019 10:29, Henning Schild wrote:
> Hey Andrej,
> 
> this feature was already proposed and discussed before, but never
> resulted in patches getting merged.
> 
> https://groups.google.com/d/topic/jailhouse-dev/BSfMKio91BQ/discussion
> 
> I did not look into it yet. But you might want to reread that thread,
> making sure your proposal covers what was discussed back than.

Thanks for the hint, I didn't really search for previous attempts.
I see now that I forgot the PEP8 formatting, will note for v3.

> The main issue really is that a lot of device drivers do not register
> themselfs as port-users, so we can not detect them.
> But those exotic ports are probably blocked in the default config so
> there is no new problem. A new problem would be if the generated configs
> shrink the default set, revoking access that was granted before.
> But i agree that it is a good idea to improve the generated config to
> reach a working out-of-the-box state.

That was my goal: old static port list and new generated ones must be
functionally the same. Access control for rest of devices is in the
hands of user, as it was before, only more handier now.

As for device detection: work is still underway.

Andrej

> 
> Henning
>

-- 
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 jailhouse-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/acbe4ed8-5e5e-dc59-abfd-b2692a0ec6f8%40st.oth-regensburg.de.
For more options, visit https://groups.google.com/d/optout.


pEpkey.asc
Description: application/pgp-keys


Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-06-28 Thread Henning Schild
Hey Andrej,

this feature was already proposed and discussed before, but never
resulted in patches getting merged.

https://groups.google.com/d/topic/jailhouse-dev/BSfMKio91BQ/discussion

I did not look into it yet. But you might want to reread that thread,
making sure your proposal covers what was discussed back than.

The main issue really is that a lot of device drivers do not register
themselfs as port-users, so we can not detect them.
But those exotic ports are probably blocked in the default config so
there is no new problem. A new problem would be if the generated configs
shrink the default set, revoking access that was granted before.

But i agree that it is a good idea to improve the generated config to
reach a working out-of-the-box state.

Henning

Am Fri, 21 Jun 2019 00:06:14 +0200
schrieb Andrej Utz :

> This replaces the old static port list with actual port regions from
> '/proc/ioports'. The static regions from said list are kept and
> override the data in case of region overlap to retain compability.
> The generated port list is virtually identicall to the old one but
> eases manual configuration.
> 
> Signed-off-by: Andrej Utz 
> ---
>  pyjailhouse/sysfs_parser.py   | 150
> ++ tools/jailhouse-config-create |
> 26 ++ tools/root-cell-config.c.tmpl |  31 ---
>  3 files changed, 176 insertions(+), 31 deletions(-)
> 
> diff --git a/pyjailhouse/sysfs_parser.py b/pyjailhouse/sysfs_parser.py
> index d612c6d3..ce490236 100644
> --- a/pyjailhouse/sysfs_parser.py
> +++ b/pyjailhouse/sysfs_parser.py
> @@ -141,6 +141,52 @@ def parse_iomem(pcidevices):
>  
>  return ret, dmar_regions
>  
> +def parse_ioports():
> +regions = IOMapTree.parse_ioports_tree(
> +IOMapTree.parse_iomap_file('/proc/ioports', PortRegion))
> +
> +tmp = [
> +# static regions
> +PortRegion(0x0, 0x3f, ''),
> +PortRegion(0x40, 0x43, 'PIT', allowed=True),
> +PortRegion(0x60, 0x61, 'NMI', allowed=True,
> comments=["HACK!"]), # NMI status/control
> +PortRegion(0x64, 0x64, 'NMI', allowed=True,
> comments=["HACK!"]), # ditto
> +PortRegion(0x70, 0x71, 'RTC', allowed=True),
> +PortRegion(0x3b0, 0x3df, 'VGA', allowed=True),
> +PortRegion(0xd00, 0x, 'PCI bus', allowed=True),
> +]
> +
> +pm_timer_base = None
> +for r in regions:
> +if r.typestr == 'ACPI PM_TMR':
> +pm_timer_base = r.start
> +
> +tmp.append(r)
> +
> +tmp.sort(key=lambda r: r.start)
> +ret = [ tmp[0] ]
> +
> +# adjust overlapping regions
> +for r in tmp[1:]:
> +prev = ret[-1]
> +
> +# combine multiple regions under the same bit mask
> +if prev.aligned_stop() >= r.aligned_start():
> +if r.stop > prev.stop:
> +n = prev
> +while n.neighbor != None:
> +n = n.neighbor
> +n.neighbor = r
> +continue
> +
> +# forbid access to unrecognized regions
> +if prev.aligned_stop() - r.aligned_start() > 0:
> +ret.append(
> +PortRegion(prev.aligned_stop() + 1,
> r.aligned_start() - 1, '')) +
> +ret.append(r)
> +
> +return (ret, pm_timer_base)
>  
>  def parse_pcidevices():
>  int_src_cnt = 0
> @@ -772,6 +818,85 @@ class MemRegion:
>  return 'JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE'
>  
>  
> +class PortRegion:
> +def __init__(self, start, stop, typestr, comments=None,
> allowed=False):
> +self.start = start
> +self.stop = stop
> +self.typestr = typestr or ''
> +self.comments = comments or []
> +self.allowed = allowed
> +self.neighbor = None
> +
> +def __str__(self):
> +# as in MemRegion this method is purely for C comment
> generation +
> +# remove consecutive duplicates
> +neighbor = self.neighbor
> +stop = self.stop
> +ns = ''
> +while neighbor:
> +if self.typestr != neighbor.typestr \
> +or self.comments != neighbor.comments:
> +ns += ', ' + str(neighbor)
> +break
> +
> +stop = neighbor.stop
> +neighbor = neighbor.neighbor
> +
> +s = ''
> +# pretty print single ports
> +if self.start == stop:
> +s += '%5s' % ''
> +else:
> +s += '%04x-' % self.start
> +
> +s += '%04x' % stop
> +
> +
> +if self.typestr:
> +s += ' : ' + self.typestr
> +
> +if self.comments:
> +s += ' (' + ', '.join(c for c in self.comments) + ')'
> +
> +s += ns
> +return s
> +
> +# used in root-cell-config.c.tmpl
> +def is_combined(self):
> +neighbor = self.neighbor
> +while neighbor:
> +if self.typestr != neighbor.typestr:
> +return True
> +
> +neighbor = neighbor.neighbor
> +
> +return False
> +
> 

Re: [PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-06-21 Thread Jan Kiszka

On 21.06.19 00:06, Andrej Utz wrote:

This replaces the old static port list with actual port regions from
'/proc/ioports'. The static regions from said list are kept and override
the data in case of region overlap to retain compability.
The generated port list is virtually identicall to the old one but eases
manual configuration.

Signed-off-by: Andrej Utz 
---
  pyjailhouse/sysfs_parser.py   | 150 ++
  tools/jailhouse-config-create |  26 ++
  tools/root-cell-config.c.tmpl |  31 ---
  3 files changed, 176 insertions(+), 31 deletions(-)

diff --git a/pyjailhouse/sysfs_parser.py b/pyjailhouse/sysfs_parser.py
index d612c6d3..ce490236 100644
--- a/pyjailhouse/sysfs_parser.py
+++ b/pyjailhouse/sysfs_parser.py
@@ -141,6 +141,52 @@ def parse_iomem(pcidevices):
  
  return ret, dmar_regions
  
+def parse_ioports():

+regions = IOMapTree.parse_ioports_tree(
+IOMapTree.parse_iomap_file('/proc/ioports', PortRegion))
+
+tmp = [
+# static regions
+PortRegion(0x0, 0x3f, ''),
+PortRegion(0x40, 0x43, 'PIT', allowed=True),
+PortRegion(0x60, 0x61, 'NMI', allowed=True, comments=["HACK!"]), # NMI 
status/control
+PortRegion(0x64, 0x64, 'NMI', allowed=True, comments=["HACK!"]), # 
ditto
+PortRegion(0x70, 0x71, 'RTC', allowed=True),
+PortRegion(0x3b0, 0x3df, 'VGA', allowed=True),
+PortRegion(0xd00, 0x, 'PCI bus', allowed=True),
+]
+
+pm_timer_base = None
+for r in regions:
+if r.typestr == 'ACPI PM_TMR':
+pm_timer_base = r.start
+
+tmp.append(r)
+
+tmp.sort(key=lambda r: r.start)
+ret = [ tmp[0] ]
+
+# adjust overlapping regions
+for r in tmp[1:]:
+prev = ret[-1]
+
+# combine multiple regions under the same bit mask
+if prev.aligned_stop() >= r.aligned_start():
+if r.stop > prev.stop:
+n = prev
+while n.neighbor != None:
+n = n.neighbor
+n.neighbor = r
+continue
+
+# forbid access to unrecognized regions
+if prev.aligned_stop() - r.aligned_start() > 0:
+ret.append(
+PortRegion(prev.aligned_stop() + 1, r.aligned_start() - 1, ''))
+
+ret.append(r)
+
+return (ret, pm_timer_base)
  
  def parse_pcidevices():

  int_src_cnt = 0
@@ -772,6 +818,85 @@ class MemRegion:
  return 'JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE'
  
  
+class PortRegion:

+def __init__(self, start, stop, typestr, comments=None, allowed=False):
+self.start = start
+self.stop = stop
+self.typestr = typestr or ''
+self.comments = comments or []
+self.allowed = allowed
+self.neighbor = None
+
+def __str__(self):
+# as in MemRegion this method is purely for C comment generation
+
+# remove consecutive duplicates
+neighbor = self.neighbor
+stop = self.stop
+ns = ''
+while neighbor:
+if self.typestr != neighbor.typestr \
+or self.comments != neighbor.comments:
+ns += ', ' + str(neighbor)
+break
+
+stop = neighbor.stop
+neighbor = neighbor.neighbor
+
+s = ''
+# pretty print single ports
+if self.start == stop:
+s += '%5s' % ''
+else:
+s += '%04x-' % self.start
+
+s += '%04x' % stop
+
+
+if self.typestr:
+s += ' : ' + self.typestr
+
+if self.comments:
+s += ' (' + ', '.join(c for c in self.comments) + ')'
+
+s += ns
+return s
+
+# used in root-cell-config.c.tmpl
+def is_combined(self):
+neighbor = self.neighbor
+while neighbor:
+if self.typestr != neighbor.typestr:
+return True
+
+neighbor = neighbor.neighbor
+
+return False
+
+def size(self):
+return self.stop - self.start
+
+def aligned_start(self):
+return self.start - self.start % 8
+
+def aligned_stop(self):
+return self.stop + (7 - self.stop % 8)
+
+def bits(self):
+# in this method: 0 = disallowed,
+# in config: 0 = allowed
+if self.allowed:
+bits = ((1 << (self.size() + 1)) - 1) << \
+(self.start - self.aligned_start())
+else:
+bits = 0
+
+if self.neighbor:
+bits |= ~self.neighbor.bits()
+
+return ~bits & 0xFF
+
+
  class IOAPIC:
  def __init__(self, id, address, gsi_base, iommu=0, bdf=0):
  self.id = id
@@ -935,6 +1060,31 @@ class IOMapTree:
  
  return regions, dmar_regions
  
+# recurse down the tree

+@staticmethod
+def parse_ioports_tree(tree):
+regions = []
+
+for tree in tree.children:
+r = tree.region
+s = r.typestr
+
+if len(tree.children) > 0:
+

[PATCH v2 2/2] pyjailhouse: x86: implement pio_bitmap generator

2019-06-20 Thread Andrej Utz
This replaces the old static port list with actual port regions from
'/proc/ioports'. The static regions from said list are kept and override
the data in case of region overlap to retain compability.
The generated port list is virtually identicall to the old one but eases
manual configuration.

Signed-off-by: Andrej Utz 
---
 pyjailhouse/sysfs_parser.py   | 150 ++
 tools/jailhouse-config-create |  26 ++
 tools/root-cell-config.c.tmpl |  31 ---
 3 files changed, 176 insertions(+), 31 deletions(-)

diff --git a/pyjailhouse/sysfs_parser.py b/pyjailhouse/sysfs_parser.py
index d612c6d3..ce490236 100644
--- a/pyjailhouse/sysfs_parser.py
+++ b/pyjailhouse/sysfs_parser.py
@@ -141,6 +141,52 @@ def parse_iomem(pcidevices):
 
 return ret, dmar_regions
 
+def parse_ioports():
+regions = IOMapTree.parse_ioports_tree(
+IOMapTree.parse_iomap_file('/proc/ioports', PortRegion))
+
+tmp = [
+# static regions
+PortRegion(0x0, 0x3f, ''),
+PortRegion(0x40, 0x43, 'PIT', allowed=True),
+PortRegion(0x60, 0x61, 'NMI', allowed=True, comments=["HACK!"]), # NMI 
status/control
+PortRegion(0x64, 0x64, 'NMI', allowed=True, comments=["HACK!"]), # 
ditto
+PortRegion(0x70, 0x71, 'RTC', allowed=True),
+PortRegion(0x3b0, 0x3df, 'VGA', allowed=True),
+PortRegion(0xd00, 0x, 'PCI bus', allowed=True),
+]
+
+pm_timer_base = None
+for r in regions:
+if r.typestr == 'ACPI PM_TMR':
+pm_timer_base = r.start
+
+tmp.append(r)
+
+tmp.sort(key=lambda r: r.start)
+ret = [ tmp[0] ]
+
+# adjust overlapping regions
+for r in tmp[1:]:
+prev = ret[-1]
+
+# combine multiple regions under the same bit mask
+if prev.aligned_stop() >= r.aligned_start():
+if r.stop > prev.stop:
+n = prev
+while n.neighbor != None:
+n = n.neighbor
+n.neighbor = r
+continue
+
+# forbid access to unrecognized regions
+if prev.aligned_stop() - r.aligned_start() > 0:
+ret.append(
+PortRegion(prev.aligned_stop() + 1, r.aligned_start() - 1, ''))
+
+ret.append(r)
+
+return (ret, pm_timer_base)
 
 def parse_pcidevices():
 int_src_cnt = 0
@@ -772,6 +818,85 @@ class MemRegion:
 return 'JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE'
 
 
+class PortRegion:
+def __init__(self, start, stop, typestr, comments=None, allowed=False):
+self.start = start
+self.stop = stop
+self.typestr = typestr or ''
+self.comments = comments or []
+self.allowed = allowed
+self.neighbor = None
+
+def __str__(self):
+# as in MemRegion this method is purely for C comment generation
+
+# remove consecutive duplicates
+neighbor = self.neighbor
+stop = self.stop
+ns = ''
+while neighbor:
+if self.typestr != neighbor.typestr \
+or self.comments != neighbor.comments:
+ns += ', ' + str(neighbor)
+break
+
+stop = neighbor.stop
+neighbor = neighbor.neighbor
+
+s = ''
+# pretty print single ports
+if self.start == stop:
+s += '%5s' % ''
+else:
+s += '%04x-' % self.start
+
+s += '%04x' % stop
+
+
+if self.typestr:
+s += ' : ' + self.typestr
+
+if self.comments:
+s += ' (' + ', '.join(c for c in self.comments) + ')'
+
+s += ns
+return s
+
+# used in root-cell-config.c.tmpl
+def is_combined(self):
+neighbor = self.neighbor
+while neighbor:
+if self.typestr != neighbor.typestr:
+return True
+
+neighbor = neighbor.neighbor
+
+return False
+
+def size(self):
+return self.stop - self.start
+
+def aligned_start(self):
+return self.start - self.start % 8
+
+def aligned_stop(self):
+return self.stop + (7 - self.stop % 8)
+
+def bits(self):
+# in this method: 0 = disallowed,
+# in config: 0 = allowed
+if self.allowed:
+bits = ((1 << (self.size() + 1)) - 1) << \
+(self.start - self.aligned_start())
+else:
+bits = 0
+
+if self.neighbor:
+bits |= ~self.neighbor.bits()
+
+return ~bits & 0xFF
+
+
 class IOAPIC:
 def __init__(self, id, address, gsi_base, iommu=0, bdf=0):
 self.id = id
@@ -935,6 +1060,31 @@ class IOMapTree:
 
 return regions, dmar_regions
 
+# recurse down the tree
+@staticmethod
+def parse_ioports_tree(tree):
+regions = []
+
+for tree in tree.children:
+r = tree.region
+s = r.typestr
+
+if len(tree.children) > 0:
+regions.extend(IOMapTree.parse_ioports_tree(tree))
+