Patchwork [13/30] memory: limit sections in the radix tree to the actual address space size

login
register
mail settings
Submitter Paolo Bonzini
Date May 21, 2013, 10:57 a.m.
Message ID <1369133851-1894-14-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/245273/
State New
Headers show

Comments

Paolo Bonzini - May 21, 2013, 10:57 a.m.
From: Avi Kivity <avi.kivity@gmail.com>

The radix tree is statically sized to fit TARGET_PHYS_ADDR_SPACE_BITS.
If a larger memory region is registered, it will overflow.

Fix by limiting any section in the radix tree to the supported size.

This problem was not observed earlier since artificial regions (containers
and aliases) are eliminated by the memory core, leaving only device regions
which have reasonable sizes.  An IOMMU however cannot be eliminated by the
memory core, and may have an artificial size.

Signed-off-by: Avi Kivity <avi.kivity@gmail.com>
[ Fail the build if TARGET_PHYS_ADDR_SPACE_BITS is too large - Paolo ]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c                | 13 ++++++++++++-
 include/exec/memory.h |  3 +++
 2 files changed, 15 insertions(+), 1 deletion(-)
Peter Maydell - May 21, 2013, 12:02 p.m.
On 21 May 2013 11:57, Paolo Bonzini <pbonzini@redhat.com> wrote:
> From: Avi Kivity <avi.kivity@gmail.com>
>
> The radix tree is statically sized to fit TARGET_PHYS_ADDR_SPACE_BITS.
> If a larger memory region is registered, it will overflow.
>
> Fix by limiting any section in the radix tree to the supported size.
>
> This problem was not observed earlier since artificial regions (containers
> and aliases) are eliminated by the memory core, leaving only device regions
> which have reasonable sizes.  An IOMMU however cannot be eliminated by the
> memory core, and may have an artificial size.
>
> Signed-off-by: Avi Kivity <avi.kivity@gmail.com>
> [ Fail the build if TARGET_PHYS_ADDR_SPACE_BITS is too large - Paolo ]
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

-- PMM

Patch

diff --git a/exec.c b/exec.c
index 380245f..8d91221 100644
--- a/exec.c
+++ b/exec.c
@@ -771,10 +771,21 @@  static void register_multipage(AddressSpaceDispatch *d, MemoryRegionSection *sec
                   section_index);
 }
 
+QEMU_BUILD_BUG_ON(TARGET_PHYS_ADDR_SPACE_BITS > MAX_PHYS_ADDR_SPACE_BITS)
+
+static MemoryRegionSection limit(MemoryRegionSection section)
+{
+    section.size = MIN(section.offset_within_address_space + section.size,
+                       MAX_PHYS_ADDR + 1)
+                   - section.offset_within_address_space;
+
+    return section;
+}
+
 static void mem_add(MemoryListener *listener, MemoryRegionSection *section)
 {
     AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener);
-    MemoryRegionSection now = *section, remain = *section;
+    MemoryRegionSection now = limit(*section), remain = limit(*section);
 
     if ((now.offset_within_address_space & ~TARGET_PAGE_MASK)
         || (now.size < TARGET_PAGE_SIZE)) {
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9fae89b..6ed593c 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -26,6 +26,9 @@ 
 #include "exec/ioport.h"
 #include "qemu/int128.h"
 
+#define MAX_PHYS_ADDR_SPACE_BITS 62
+#define MAX_PHYS_ADDR            (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1)
+
 typedef struct MemoryRegionOps MemoryRegionOps;
 typedef struct MemoryRegionPortio MemoryRegionPortio;
 typedef struct MemoryRegionMmio MemoryRegionMmio;