diff mbox

[QEMU,RFC,3/6] memory: Add xen memory hook

Message ID e423998b589b9ce6cfef087f0af6f37f4277da46.1332430835.git.julien.grall@citrix.com
State New
Headers show

Commit Message

Julien Grall March 22, 2012, 4:01 p.m. UTC
QEMU will now register all memory range (PIO and MMIO) in Xen.
We distinct two phases in memory registered :
  - initialization
  - running

For all range registered during the initialization, QEMU will
check with XenStore if it is authorized to use them.
After the initialization, QEMU can register all range. Indeed,
the new ranges will be for PCI Bar.

Signed-off-by: Julien Grall <julien.grall@citrix.com>
---
 exec.c    |    9 ++++++
 ioport.c  |   17 ++++++++++++
 xen-all.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 109 insertions(+), 0 deletions(-)

Comments

Julien Grall March 23, 2012, 3:08 p.m. UTC | #1
On 03/22/2012 05:44 PM, Jan Kiszka wrote:
>>
>>   static void core_region_nop(MemoryListener *listener,
>> diff --git a/ioport.c b/ioport.c
>> index 78a3b89..073ed75 100644
>> --- a/ioport.c
>> +++ b/ioport.c
>> @@ -28,6 +28,7 @@
>>   #include "ioport.h"
>>   #include "trace.h"
>>   #include "memory.h"
>> +#include "hw/xen.h"
>>
>>   /***********************************************************/
>>   /* IO Port */
>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int length, int size,
>>                        i);
>>           ioport_opaque[i] = opaque;
>>       }
>> +
>> +    if (xen_enabled()) {
>> +        xen_map_iorange(start, length, 0);
>> +    }
>> +
>>       return 0;
>>   }
>>
>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int length, int size,
>>                        i);
>>           ioport_opaque[i] = opaque;
>>       }
>> +
>> +    if (xen_enabled()) {
>> +        xen_map_iorange(start, length, 0);
>> +    }
>> +
>>       return 0;
>> +
>>   }
>>
>>   static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int length)
>>           ioport_destructor_table[start](ioport_opaque[start]);
>>           ioport_destructor_table[start] = NULL;
>>       }
>> +
>> +    if (xen_enabled()) {
>> +        xen_unmap_iorange(start, length, 0);
>> +    }
>> +
>>       for(i = start; i<  start + length; i++) {
>>           ioport_read_table[0][i] = NULL;
>>           ioport_read_table[1][i] = NULL;
>>      
> memory_listener_register(xen_hooks, system_io)?
>    
QEMU doesn't seem to call region_add/region_del for ioport.
Moreover, some of ioport are directly register without
using memory hook (for example cirrus vga).

What is the best way to do it ?

> Even if that is not yet powerful enough, tuning the hooks is usually
> better than open-coding.
>
> Jan
>
>
Jan Kiszka March 23, 2012, 4:37 p.m. UTC | #2
On 2012-03-23 16:08, Julien Grall wrote:
> On 03/22/2012 05:44 PM, Jan Kiszka wrote:
>>>
>>>   static void core_region_nop(MemoryListener *listener,
>>> diff --git a/ioport.c b/ioport.c
>>> index 78a3b89..073ed75 100644
>>> --- a/ioport.c
>>> +++ b/ioport.c
>>> @@ -28,6 +28,7 @@
>>>   #include "ioport.h"
>>>   #include "trace.h"
>>>   #include "memory.h"
>>> +#include "hw/xen.h"
>>>
>>>   /***********************************************************/
>>>   /* IO Port */
>>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int
>>> length, int size,
>>>                        i);
>>>           ioport_opaque[i] = opaque;
>>>       }
>>> +
>>> +    if (xen_enabled()) {
>>> +        xen_map_iorange(start, length, 0);
>>> +    }
>>> +
>>>       return 0;
>>>   }
>>>
>>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int
>>> length, int size,
>>>                        i);
>>>           ioport_opaque[i] = opaque;
>>>       }
>>> +
>>> +    if (xen_enabled()) {
>>> +        xen_map_iorange(start, length, 0);
>>> +    }
>>> +
>>>       return 0;
>>> +
>>>   }
>>>
>>>   static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
>>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int
>>> length)
>>>           ioport_destructor_table[start](ioport_opaque[start]);
>>>           ioport_destructor_table[start] = NULL;
>>>       }
>>> +
>>> +    if (xen_enabled()) {
>>> +        xen_unmap_iorange(start, length, 0);
>>> +    }
>>> +
>>>       for(i = start; i<  start + length; i++) {
>>>           ioport_read_table[0][i] = NULL;
>>>           ioport_read_table[1][i] = NULL;
>>>      
>> memory_listener_register(xen_hooks, system_io)?
>>    
> QEMU doesn't seem to call region_add/region_del for ioport.
> Moreover, some of ioport are directly register without
> using memory hook (for example cirrus vga).
> 
> What is the best way to do it ?

I haven't looked at details. Maybe it is just a combination of "use case
not yet considered, but can easily be added" and "need to switch legacy
code to new scheme". Then this still remains the better option than this
hook. Avi?

Jan
Anthony Liguori March 23, 2012, 4:47 p.m. UTC | #3
On 03/22/2012 11:01 AM, Julien Grall wrote:
> QEMU will now register all memory range (PIO and MMIO) in Xen.
> We distinct two phases in memory registered :
>    - initialization
>    - running
>
> For all range registered during the initialization, QEMU will
> check with XenStore if it is authorized to use them.
> After the initialization, QEMU can register all range. Indeed,
> the new ranges will be for PCI Bar.
>
> Signed-off-by: Julien Grall<julien.grall@citrix.com>
> ---
>   exec.c    |    9 ++++++
>   ioport.c  |   17 ++++++++++++
>   xen-all.c |   83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 109 insertions(+), 0 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index 780f63f..42d8c56 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3557,12 +3557,21 @@ static void core_commit(MemoryListener *listener)
>   static void core_region_add(MemoryListener *listener,
>                               MemoryRegionSection *section)
>   {
> +    if (xen_enabled()) {
> +       xen_map_iorange(section->offset_within_address_space,
> +                       section->size, 1);
> +    }
> +
>       cpu_register_physical_memory_log(section, section->readonly);
>   }
>
>   static void core_region_del(MemoryListener *listener,
>                               MemoryRegionSection *section)
>   {
> +    if (xen_enabled()) {
> +       xen_unmap_iorange(section->offset_within_address_space,
> +                       section->size, 1);
> +    }
>   }
>
>   static void core_region_nop(MemoryListener *listener,
> diff --git a/ioport.c b/ioport.c
> index 78a3b89..073ed75 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -28,6 +28,7 @@
>   #include "ioport.h"
>   #include "trace.h"
>   #include "memory.h"
> +#include "hw/xen.h"
>
>   /***********************************************************/
>   /* IO Port */
> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int length, int size,
>                        i);
>           ioport_opaque[i] = opaque;
>       }
> +
> +    if (xen_enabled()) {
> +        xen_map_iorange(start, length, 0);
> +    }
> +
>       return 0;
>   }
>
> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int length, int size,
>                        i);
>           ioport_opaque[i] = opaque;
>       }
> +
> +    if (xen_enabled()) {
> +        xen_map_iorange(start, length, 0);
> +    }
> +
>       return 0;
> +
>   }


This is the opposite direction we need to head.

I really don't think this series is the right way to handle things.  I don't 
want to see random hooks throughout QEMU to intercept for APIs affectively 
disabling large chunks of QEMU in the process.

You should look at (1) creating only the devices you want (2) use a clean 
interface to interact with those devices.

That would mean having a Xen specific AddressSpaceOps for ioports or something 
like that.  Not having hooks in areas of code like this.

Regards,

Anthony Liguori
Avi Kivity March 25, 2012, 10:44 a.m. UTC | #4
On 03/23/2012 06:37 PM, Jan Kiszka wrote:
> On 2012-03-23 16:08, Julien Grall wrote:
> > On 03/22/2012 05:44 PM, Jan Kiszka wrote:
> >>>
> >>>   static void core_region_nop(MemoryListener *listener,
> >>> diff --git a/ioport.c b/ioport.c
> >>> index 78a3b89..073ed75 100644
> >>> --- a/ioport.c
> >>> +++ b/ioport.c
> >>> @@ -28,6 +28,7 @@
> >>>   #include "ioport.h"
> >>>   #include "trace.h"
> >>>   #include "memory.h"
> >>> +#include "hw/xen.h"
> >>>
> >>>   /***********************************************************/
> >>>   /* IO Port */
> >>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int
> >>> length, int size,
> >>>                        i);
> >>>           ioport_opaque[i] = opaque;
> >>>       }
> >>> +
> >>> +    if (xen_enabled()) {
> >>> +        xen_map_iorange(start, length, 0);
> >>> +    }
> >>> +
> >>>       return 0;
> >>>   }
> >>>
> >>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int
> >>> length, int size,
> >>>                        i);
> >>>           ioport_opaque[i] = opaque;
> >>>       }
> >>> +
> >>> +    if (xen_enabled()) {
> >>> +        xen_map_iorange(start, length, 0);
> >>> +    }
> >>> +
> >>>       return 0;
> >>> +
> >>>   }
> >>>
> >>>   static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
> >>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int
> >>> length)
> >>>           ioport_destructor_table[start](ioport_opaque[start]);
> >>>           ioport_destructor_table[start] = NULL;
> >>>       }
> >>> +
> >>> +    if (xen_enabled()) {
> >>> +        xen_unmap_iorange(start, length, 0);
> >>> +    }
> >>> +
> >>>       for(i = start; i<  start + length; i++) {
> >>>           ioport_read_table[0][i] = NULL;
> >>>           ioport_read_table[1][i] = NULL;
> >>>      
> >> memory_listener_register(xen_hooks, system_io)?
> >>    
> > QEMU doesn't seem to call region_add/region_del for ioport.
> > Moreover, some of ioport are directly register without
> > using memory hook (for example cirrus vga).
> > 
> > What is the best way to do it ?
>
> I haven't looked at details. Maybe it is just a combination of "use case
> not yet considered, but can easily be added" and "need to switch legacy
> code to new scheme". Then this still remains the better option than this
> hook. Avi?

Just the second - region_add/del will be called, but only for ioports
registered via the MemoryRegion APIs.
Stefano Stabellini March 26, 2012, 11:01 a.m. UTC | #5
On Sun, 25 Mar 2012, Avi Kivity wrote:
> On 03/23/2012 06:37 PM, Jan Kiszka wrote:
> > On 2012-03-23 16:08, Julien Grall wrote:
> > > On 03/22/2012 05:44 PM, Jan Kiszka wrote:
> > >>>
> > >>>   static void core_region_nop(MemoryListener *listener,
> > >>> diff --git a/ioport.c b/ioport.c
> > >>> index 78a3b89..073ed75 100644
> > >>> --- a/ioport.c
> > >>> +++ b/ioport.c
> > >>> @@ -28,6 +28,7 @@
> > >>>   #include "ioport.h"
> > >>>   #include "trace.h"
> > >>>   #include "memory.h"
> > >>> +#include "hw/xen.h"
> > >>>
> > >>>   /***********************************************************/
> > >>>   /* IO Port */
> > >>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int
> > >>> length, int size,
> > >>>                        i);
> > >>>           ioport_opaque[i] = opaque;
> > >>>       }
> > >>> +
> > >>> +    if (xen_enabled()) {
> > >>> +        xen_map_iorange(start, length, 0);
> > >>> +    }
> > >>> +
> > >>>       return 0;
> > >>>   }
> > >>>
> > >>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int
> > >>> length, int size,
> > >>>                        i);
> > >>>           ioport_opaque[i] = opaque;
> > >>>       }
> > >>> +
> > >>> +    if (xen_enabled()) {
> > >>> +        xen_map_iorange(start, length, 0);
> > >>> +    }
> > >>> +
> > >>>       return 0;
> > >>> +
> > >>>   }
> > >>>
> > >>>   static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
> > >>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int
> > >>> length)
> > >>>           ioport_destructor_table[start](ioport_opaque[start]);
> > >>>           ioport_destructor_table[start] = NULL;
> > >>>       }
> > >>> +
> > >>> +    if (xen_enabled()) {
> > >>> +        xen_unmap_iorange(start, length, 0);
> > >>> +    }
> > >>> +
> > >>>       for(i = start; i<  start + length; i++) {
> > >>>           ioport_read_table[0][i] = NULL;
> > >>>           ioport_read_table[1][i] = NULL;
> > >>>      
> > >> memory_listener_register(xen_hooks, system_io)?
> > >>    
> > > QEMU doesn't seem to call region_add/region_del for ioport.
> > > Moreover, some of ioport are directly register without
> > > using memory hook (for example cirrus vga).
> > > 
> > > What is the best way to do it ?
> >
> > I haven't looked at details. Maybe it is just a combination of "use case
> > not yet considered, but can easily be added" and "need to switch legacy
> > code to new scheme". Then this still remains the better option than this
> > hook. Avi?
> 
> Just the second - region_add/del will be called, but only for ioports
> registered via the MemoryRegion APIs.

It looks like there are quite a few register_ioport_read/write left
around, especially in the following files:

hw/acpi_piix4.c
hw/cirrus_vga.c
hw/serial.c
hw/pckbd.c
hw/pc.c

I guess they should all be converted to memory_region_init_io, right?
Avi Kivity March 26, 2012, 11:02 a.m. UTC | #6
On 03/26/2012 01:01 PM, Stefano Stabellini wrote:
> On Sun, 25 Mar 2012, Avi Kivity wrote:
> > On 03/23/2012 06:37 PM, Jan Kiszka wrote:
> > > On 2012-03-23 16:08, Julien Grall wrote:
> > > > On 03/22/2012 05:44 PM, Jan Kiszka wrote:
> > > >>>
> > > >>>   static void core_region_nop(MemoryListener *listener,
> > > >>> diff --git a/ioport.c b/ioport.c
> > > >>> index 78a3b89..073ed75 100644
> > > >>> --- a/ioport.c
> > > >>> +++ b/ioport.c
> > > >>> @@ -28,6 +28,7 @@
> > > >>>   #include "ioport.h"
> > > >>>   #include "trace.h"
> > > >>>   #include "memory.h"
> > > >>> +#include "hw/xen.h"
> > > >>>
> > > >>>   /***********************************************************/
> > > >>>   /* IO Port */
> > > >>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int
> > > >>> length, int size,
> > > >>>                        i);
> > > >>>           ioport_opaque[i] = opaque;
> > > >>>       }
> > > >>> +
> > > >>> +    if (xen_enabled()) {
> > > >>> +        xen_map_iorange(start, length, 0);
> > > >>> +    }
> > > >>> +
> > > >>>       return 0;
> > > >>>   }
> > > >>>
> > > >>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int
> > > >>> length, int size,
> > > >>>                        i);
> > > >>>           ioport_opaque[i] = opaque;
> > > >>>       }
> > > >>> +
> > > >>> +    if (xen_enabled()) {
> > > >>> +        xen_map_iorange(start, length, 0);
> > > >>> +    }
> > > >>> +
> > > >>>       return 0;
> > > >>> +
> > > >>>   }
> > > >>>
> > > >>>   static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
> > > >>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int
> > > >>> length)
> > > >>>           ioport_destructor_table[start](ioport_opaque[start]);
> > > >>>           ioport_destructor_table[start] = NULL;
> > > >>>       }
> > > >>> +
> > > >>> +    if (xen_enabled()) {
> > > >>> +        xen_unmap_iorange(start, length, 0);
> > > >>> +    }
> > > >>> +
> > > >>>       for(i = start; i<  start + length; i++) {
> > > >>>           ioport_read_table[0][i] = NULL;
> > > >>>           ioport_read_table[1][i] = NULL;
> > > >>>      
> > > >> memory_listener_register(xen_hooks, system_io)?
> > > >>    
> > > > QEMU doesn't seem to call region_add/region_del for ioport.
> > > > Moreover, some of ioport are directly register without
> > > > using memory hook (for example cirrus vga).
> > > > 
> > > > What is the best way to do it ?
> > >
> > > I haven't looked at details. Maybe it is just a combination of "use case
> > > not yet considered, but can easily be added" and "need to switch legacy
> > > code to new scheme". Then this still remains the better option than this
> > > hook. Avi?
> > 
> > Just the second - region_add/del will be called, but only for ioports
> > registered via the MemoryRegion APIs.
>
> It looks like there are quite a few register_ioport_read/write left
> around, especially in the following files:
>
> hw/acpi_piix4.c
> hw/cirrus_vga.c
> hw/serial.c
> hw/pckbd.c
> hw/pc.c
>
> I guess they should all be converted to memory_region_init_io, right?

Right.
Julien Grall March 26, 2012, 11:24 a.m. UTC | #7
On 03/26/2012 12:02 PM, Avi Kivity wrote:
> On 03/26/2012 01:01 PM, Stefano Stabellini wrote:
>    
>> On Sun, 25 Mar 2012, Avi Kivity wrote:
>>      
>>> On 03/23/2012 06:37 PM, Jan Kiszka wrote:
>>>        
>>>> On 2012-03-23 16:08, Julien Grall wrote:
>>>>          
>>>>> On 03/22/2012 05:44 PM, Jan Kiszka wrote:
>>>>>            
>>>>>>>    static void core_region_nop(MemoryListener *listener,
>>>>>>> diff --git a/ioport.c b/ioport.c
>>>>>>> index 78a3b89..073ed75 100644
>>>>>>> --- a/ioport.c
>>>>>>> +++ b/ioport.c
>>>>>>> @@ -28,6 +28,7 @@
>>>>>>>    #include "ioport.h"
>>>>>>>    #include "trace.h"
>>>>>>>    #include "memory.h"
>>>>>>> +#include "hw/xen.h"
>>>>>>>
>>>>>>>    /***********************************************************/
>>>>>>>    /* IO Port */
>>>>>>> @@ -155,6 +156,11 @@ int register_ioport_read(pio_addr_t start, int
>>>>>>> length, int size,
>>>>>>>                         i);
>>>>>>>            ioport_opaque[i] = opaque;
>>>>>>>        }
>>>>>>> +
>>>>>>> +    if (xen_enabled()) {
>>>>>>> +        xen_map_iorange(start, length, 0);
>>>>>>> +    }
>>>>>>> +
>>>>>>>        return 0;
>>>>>>>    }
>>>>>>>
>>>>>>> @@ -175,7 +181,13 @@ int register_ioport_write(pio_addr_t start, int
>>>>>>> length, int size,
>>>>>>>                         i);
>>>>>>>            ioport_opaque[i] = opaque;
>>>>>>>        }
>>>>>>> +
>>>>>>> +    if (xen_enabled()) {
>>>>>>> +        xen_map_iorange(start, length, 0);
>>>>>>> +    }
>>>>>>> +
>>>>>>>        return 0;
>>>>>>> +
>>>>>>>    }
>>>>>>>
>>>>>>>    static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
>>>>>>> @@ -260,6 +272,11 @@ void isa_unassign_ioport(pio_addr_t start, int
>>>>>>> length)
>>>>>>>            ioport_destructor_table[start](ioport_opaque[start]);
>>>>>>>            ioport_destructor_table[start] = NULL;
>>>>>>>        }
>>>>>>> +
>>>>>>> +    if (xen_enabled()) {
>>>>>>> +        xen_unmap_iorange(start, length, 0);
>>>>>>> +    }
>>>>>>> +
>>>>>>>        for(i = start; i<   start + length; i++) {
>>>>>>>            ioport_read_table[0][i] = NULL;
>>>>>>>            ioport_read_table[1][i] = NULL;
>>>>>>>
>>>>>>>                
>>>>>> memory_listener_register(xen_hooks, system_io)?
>>>>>>
>>>>>>              
>>>>> QEMU doesn't seem to call region_add/region_del for ioport.
>>>>> Moreover, some of ioport are directly register without
>>>>> using memory hook (for example cirrus vga).
>>>>>
>>>>> What is the best way to do it ?
>>>>>            
>>>> I haven't looked at details. Maybe it is just a combination of "use case
>>>> not yet considered, but can easily be added" and "need to switch legacy
>>>> code to new scheme". Then this still remains the better option than this
>>>> hook. Avi?
>>>>          
>>> Just the second - region_add/del will be called, but only for ioports
>>> registered via the MemoryRegion APIs.
>>>        
>> It looks like there are quite a few register_ioport_read/write left
>> around, especially in the following files:
>>
>> hw/acpi_piix4.c
>> hw/cirrus_vga.c
>> hw/serial.c
>> hw/pckbd.c
>> hw/pc.c
>>
>> I guess they should all be converted to memory_region_init_io, right?
>>      
> Right
I will modify theses files and send a different patch series.
Avi Kivity March 26, 2012, 1:13 p.m. UTC | #8
On 03/26/2012 01:24 PM, Julien Grall wrote:
>>> It looks like there are quite a few register_ioport_read/write left
>>> around, especially in the following files:
>>>
>>> hw/acpi_piix4.c
>>> hw/cirrus_vga.c
>>> hw/serial.c
>>> hw/pckbd.c
>>> hw/pc.c
>>>
>>> I guess they should all be converted to memory_region_init_io, right?
>>>      
>> Right
>        I will modify theses files and send a different patch series.
>

Great.  Please post them as a separate series, they can go in relatively
quickly since they should be mostly straighforward.
diff mbox

Patch

diff --git a/exec.c b/exec.c
index 780f63f..42d8c56 100644
--- a/exec.c
+++ b/exec.c
@@ -3557,12 +3557,21 @@  static void core_commit(MemoryListener *listener)
 static void core_region_add(MemoryListener *listener,
                             MemoryRegionSection *section)
 {
+    if (xen_enabled()) {
+       xen_map_iorange(section->offset_within_address_space,
+                       section->size, 1);
+    }
+
     cpu_register_physical_memory_log(section, section->readonly);
 }
 
 static void core_region_del(MemoryListener *listener,
                             MemoryRegionSection *section)
 {
+    if (xen_enabled()) {
+       xen_unmap_iorange(section->offset_within_address_space,
+                       section->size, 1);
+    }
 }
 
 static void core_region_nop(MemoryListener *listener,
diff --git a/ioport.c b/ioport.c
index 78a3b89..073ed75 100644
--- a/ioport.c
+++ b/ioport.c
@@ -28,6 +28,7 @@ 
 #include "ioport.h"
 #include "trace.h"
 #include "memory.h"
+#include "hw/xen.h"
 
 /***********************************************************/
 /* IO Port */
@@ -155,6 +156,11 @@  int register_ioport_read(pio_addr_t start, int length, int size,
                      i);
         ioport_opaque[i] = opaque;
     }
+
+    if (xen_enabled()) {
+        xen_map_iorange(start, length, 0);
+    }
+
     return 0;
 }
 
@@ -175,7 +181,13 @@  int register_ioport_write(pio_addr_t start, int length, int size,
                      i);
         ioport_opaque[i] = opaque;
     }
+
+    if (xen_enabled()) {
+        xen_map_iorange(start, length, 0);
+    }
+
     return 0;
+
 }
 
 static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
@@ -260,6 +272,11 @@  void isa_unassign_ioport(pio_addr_t start, int length)
         ioport_destructor_table[start](ioport_opaque[start]);
         ioport_destructor_table[start] = NULL;
     }
+
+    if (xen_enabled()) {
+        xen_unmap_iorange(start, length, 0);
+    }
+
     for(i = start; i < start + length; i++) {
         ioport_read_table[0][i] = NULL;
         ioport_read_table[1][i] = NULL;
diff --git a/xen-all.c b/xen-all.c
index f007278..366bafe 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -124,6 +124,89 @@  void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
     }
 }
 
+static void str_to_range(const char *str, uint64_t *begin, uint64_t *end)
+{
+    char *buf;
+
+    /* We assume that range is valid  */
+    *begin = strtoll(str, &buf, 0);
+    if (buf[0] == '\0') {
+        *end = *begin;
+        return;
+    }
+
+    str = buf + 1;
+    *end = strtoll(str, &buf, 0);
+}
+
+static int check_range(uint64_t addr, uint64_t size, int is_mmio)
+{
+    struct xs_handle *xs = NULL;
+    char **dir;
+    char *str;
+    int rc = 1;
+    int i;
+    uint64_t begin;
+    uint64_t end;
+    char base[70];
+    char path[70];
+    unsigned int nb;
+    unsigned int len;
+
+    xs = xs_open(0);
+    if (!xs) {
+        fprintf(stderr, "check_range: unable to open xenstore\n");
+        return 1;
+    }
+
+    snprintf(base, sizeof (base), "/local/domain/%u/image/dms/%u/%s",
+             xen_domid, xen_dmid, (is_mmio) ? "mmio" : "pio");
+    dir = xs_directory(xs, XBT_NULL, base, &nb);
+
+    if (dir) {
+        for (i = 0; i < nb; i++) {
+            snprintf(path, sizeof (path), "%s/%s", base, dir[i]);
+            str = xs_read(xs, XBT_NULL, path, &len);
+            str_to_range(str, &begin, &end);
+            free(str);
+            if (addr == begin && (addr + size - 1) == end) {
+                rc = 0;
+                break;
+            }
+        }
+        free(dir);
+    }
+
+    return rc;
+}
+
+void xen_map_iorange(uint64_t addr, uint64_t size, int is_mmio)
+{
+    static uint64_t previous_addr = ~0;
+
+    /* Don't register multiple times the same ioport */
+    if (!is_mmio) {
+        if (addr == previous_addr)
+            return;
+        previous_addr = addr;
+    }
+
+    if (!is_running) {
+        if (check_range(addr, size, is_mmio)) {
+            return;
+        }
+    }
+
+    xc_hvm_map_io_range_to_ioreq_server(xen_xc, xen_domid, serverid, is_mmio,
+                                        addr, addr + size - 1);
+}
+
+void xen_unmap_iorange(uint64_t addr, uint64_t size, int is_mmio)
+{
+    xc_hvm_unmap_io_range_from_ioreq_server(xen_xc, xen_domid, serverid, is_mmio,
+                                            addr);
+}
+
 static void xen_suspend_notifier(Notifier *notifier, void *data)
 {
     xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 3);