[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [IA64] Allow dynamic allocation of dom0 fw_tables



# HG changeset patch
# User Alex Williamson <alex.williamson@xxxxxx>
# Date 1180987028 21600
# Node ID c0cdcebc0377f817155587cd83da79b234f769a5
# Parent  b46c2ff6dfb0de75e17fee01f0adc4d35d5e8322
[IA64] Allow dynamic allocation of dom0 fw_tables

This address Xensource bugzilla #980

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
---
 tools/libxc/ia64/xc_dom_ia64_util.c  |   29 ++++-
 tools/libxc/ia64/xc_dom_ia64_util.h  |    2 
 xen/arch/ia64/xen/dom_fw_common.c    |   44 ++++----
 xen/arch/ia64/xen/dom_fw_dom0.c      |  183 ++++++++++++++++++++---------------
 xen/arch/ia64/xen/dom_fw_domu.c      |   75 ++++++++------
 xen/arch/ia64/xen/dom_fw_utils.c     |  160 ++++++++++++++++++++++++------
 xen/include/asm-ia64/dom_fw.h        |    5 
 xen/include/asm-ia64/dom_fw_common.h |   14 ++
 xen/include/asm-ia64/dom_fw_dom0.h   |    6 -
 xen/include/asm-ia64/dom_fw_domu.h   |    2 
 xen/include/asm-ia64/dom_fw_utils.h  |    4 
 11 files changed, 351 insertions(+), 173 deletions(-)

diff -r b46c2ff6dfb0 -r c0cdcebc0377 tools/libxc/ia64/xc_dom_ia64_util.c
--- a/tools/libxc/ia64/xc_dom_ia64_util.c       Thu May 31 14:47:08 2007 -0600
+++ b/tools/libxc/ia64/xc_dom_ia64_util.c       Mon Jun 04 13:57:08 2007 -0600
@@ -18,6 +18,7 @@
  *
  */
 
+#include <assert.h>
 #include "xg_private.h"
 #include "xc_dom.h"
 #include "asm/dom_fw.h"
@@ -114,12 +115,12 @@ xen_ia64_dom_fw_setup(struct xc_dom_imag
 {
     int rc = 0;
     void *imva_hypercall_base = NULL;
-    void *imva_tables_base = NULL;
+    struct fw_tables *fw_tables = NULL;
     struct fake_acpi_tables *imva = NULL;
     struct xen_ia64_boot_param *bp = NULL;
 
     BUILD_BUG_ON(sizeof(struct fw_tables) >
-                 (FW_TABLES_END_PADDR - FW_TABLES_BASE_PADDR));
+                 (FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR));
 
     /* Create page for hypercalls.  */
     imva_hypercall_base = xen_ia64_dom_fw_map(d, FW_HYPERCALL_BASE_PADDR);
@@ -129,11 +130,17 @@ xen_ia64_dom_fw_setup(struct xc_dom_imag
     }
 
     /* Create page for FW tables.  */
-    imva_tables_base = xen_ia64_dom_fw_map(d, FW_TABLES_BASE_PADDR);
-    if (imva_tables_base == NULL) {
+    fw_tables = (struct fw_tables*)xen_ia64_dom_fw_map(d, 
FW_TABLES_BASE_PADDR);
+    if (fw_tables == NULL) {
         rc = -errno;
         goto out;
     }
+    memset(fw_tables, 0, FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR);
+    BUILD_BUG_ON(FW_END_PADDR_MIN != FW_TABLES_END_PADDR_MIN);
+    fw_tables->fw_tables_size = FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR;
+    fw_tables->fw_end_paddr = FW_END_PADDR_MIN;
+    fw_tables->fw_tables_end_paddr = FW_TABLES_END_PADDR_MIN;
+    fw_tables->num_mds = 0;
         
     /* Create page for acpi tables.  */
     imva = (struct fake_acpi_tables *)
@@ -150,14 +157,22 @@ xen_ia64_dom_fw_setup(struct xc_dom_imag
         rc = -errno;
         goto out;
     }
-    rc = dom_fw_init(d, brkimm, bp, imva_tables_base,
+    rc = dom_fw_init(d, brkimm, bp, fw_tables,
                      (unsigned long)imva_hypercall_base, maxmem);
+    BUG_ON(fw_tables->fw_tables_size < sizeof(*fw_tables) +
+           sizeof(fw_tables->efi_memmap[0]) * fw_tables->num_mds);
 
+    /* clear domain builder internal use member */
+    fw_tables->fw_tables_size = 0;
+    fw_tables->fw_end_paddr = 0;
+    fw_tables->fw_tables_end_paddr = 0;
+    fw_tables->num_mds = 0;
+    
  out:
     if (imva_hypercall_base != NULL)
         xen_ia64_dom_fw_unmap(d, imva_hypercall_base);
-    if (imva_tables_base != NULL)
-        xen_ia64_dom_fw_unmap(d, imva_tables_base);
+    if (fw_tables != NULL)
+        xen_ia64_dom_fw_unmap(d, fw_tables);
     if (imva != NULL)
         xen_ia64_dom_fw_unmap(d, imva);
     if (bp != NULL)
diff -r b46c2ff6dfb0 -r c0cdcebc0377 tools/libxc/ia64/xc_dom_ia64_util.h
--- a/tools/libxc/ia64/xc_dom_ia64_util.h       Thu May 31 14:47:08 2007 -0600
+++ b/tools/libxc/ia64/xc_dom_ia64_util.h       Mon Jun 04 13:57:08 2007 -0600
@@ -14,6 +14,6 @@ xen_ia64_dom_fw_setup(struct xc_dom_imag
 xen_ia64_dom_fw_setup(struct xc_dom_image *d, uint64_t brkimm,
                       unsigned long bp_mpa, unsigned long maxmem);
 #define efi_systable_init_dom0(tables) assert(0)
-#define complete_dom0_memmap(d, tables, maxmem, num_mds) ({assert(0);0;})
+#define complete_dom0_memmap(d, tables) ({assert(0);0;})
 
 #endif /* XC_IA64_DOM_IA64_UTIL_H */
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/arch/ia64/xen/dom_fw_common.c
--- a/xen/arch/ia64/xen/dom_fw_common.c Thu May 31 14:47:08 2007 -0600
+++ b/xen/arch/ia64/xen/dom_fw_common.c Mon Jun 04 13:57:08 2007 -0600
@@ -35,22 +35,17 @@
 #include <asm/dom_fw_domu.h>
 
 void
-xen_ia64_efi_make_md(struct fw_tables *tables, int *index,
+xen_ia64_efi_make_md(efi_memory_desc_t *md,
                     uint32_t type, uint64_t attr, 
                     uint64_t start, uint64_t end)
 {
-       efi_memory_desc_t *md = &tables->efi_memmap[*index];
        md->type = type;
        md->pad = 0;
        md->phys_addr = start;
        md->virt_addr = 0;
        md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
        md->attribute = attr;
-
-       (*index)++;
-}
-#define MAKE_MD(typ, attr, start, end) \
-       xen_ia64_efi_make_md((tables), &(i), (typ), (attr), (start), (end))
+}
 
 #define EFI_HYPERCALL_PATCH(tgt, call)                                 \
        do {                                                            \
@@ -422,7 +417,7 @@ dom_fw_init(domain_t *d,
        int num_mds, i;
        int fpswa_supported = 0;
 
-       memset(tables, 0, sizeof(struct fw_tables));
+       /* Caller must zero-clear fw_tables */
 
        /* EFI systab.  */
        tables->efi_systab.hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
@@ -514,17 +509,25 @@ dom_fw_init(domain_t *d,
                        (void *)FW_HYPERCALL_FPSWA_ENTRY_PADDR;
        }
 
-       i = 0; /* Used by MAKE_MD */
-
+       tables->num_mds = 0;
        /* hypercall patches live here, masquerade as reserved PAL memory */
-       MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB|EFI_MEMORY_RUNTIME,
-               FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR);
+       xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds],
+                            EFI_PAL_CODE, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
+                            FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR);
+       tables->num_mds++;
 
        /* Create dom0/domu md entry for fw and cpi tables area.  */
-       MAKE_MD(EFI_ACPI_MEMORY_NVS, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
-               FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR);
-       MAKE_MD(EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
-               FW_TABLES_BASE_PADDR, FW_TABLES_END_PADDR);
+       xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds],
+                            EFI_ACPI_MEMORY_NVS,
+                            EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
+                            FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR);
+       tables->num_mds++;
+       xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds],
+                            EFI_RUNTIME_SERVICES_DATA,
+                            EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
+                            FW_TABLES_BASE_PADDR,
+                            tables->fw_tables_end_paddr);
+       tables->num_mds++;
 
        if (!xen_ia64_is_dom0(d) || xen_ia64_is_running_on_sim(d)) {
                /* DomU (or hp-ski).
@@ -536,26 +539,27 @@ dom_fw_init(domain_t *d,
                 * and console page.
                 * see ia64_setup_memmap() @ xc_dom_boot.c
                 */
-               num_mds = complete_domu_memmap(d, tables, maxmem, i,
+               num_mds = complete_domu_memmap(d, tables, maxmem,
                                               XEN_IA64_MEMMAP_INFO_PFN(bp),
                                               
XEN_IA64_MEMMAP_INFO_NUM_PAGES(bp));
        } else {
                /* Dom0.
                   We must preserve ACPI data from real machine,
                   as well as IO areas.  */
-               num_mds = complete_dom0_memmap(d, tables, maxmem, i);
+               num_mds = complete_dom0_memmap(d, tables);
        }
        if (num_mds < 0)
                return num_mds;
+       BUG_ON(num_mds != tables->num_mds);
 
        /* Display memmap.  */
-       for (i = 0 ; i < num_mds; i++)
+       for (i = 0 ; i < tables->num_mds; i++)
                print_md(&tables->efi_memmap[i]);
 
        /* Fill boot_param  */
        bp->efi_systab = FW_FIELD_MPA(efi_systab);
        bp->efi_memmap = FW_FIELD_MPA(efi_memmap);
-       bp->efi_memmap_size = num_mds * sizeof(efi_memory_desc_t);
+       bp->efi_memmap_size = tables->num_mds * sizeof(efi_memory_desc_t);
        bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
        bp->efi_memdesc_version = EFI_MEMDESC_VERSION;
        bp->command_line = 0;
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/arch/ia64/xen/dom_fw_dom0.c
--- a/xen/arch/ia64/xen/dom_fw_dom0.c   Thu May 31 14:47:08 2007 -0600
+++ b/xen/arch/ia64/xen/dom_fw_dom0.c   Mon Jun 04 13:57:08 2007 -0600
@@ -32,6 +32,7 @@
 #include <asm/dom_fw.h>
 #include <asm/dom_fw_common.h>
 #include <asm/dom_fw_dom0.h>
+#include <asm/dom_fw_utils.h>
 
 #include <linux/sort.h>
 
@@ -158,21 +159,26 @@ void __init efi_systable_init_dom0(struc
 }
 
 static void __init
-setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables, int 
*num_mds)
+setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables)
 {
        int i;
+       size_t size;
+       unsigned int num_pages;
        efi_memory_desc_t *md;
        efi_memory_desc_t *last_mem_md = NULL;
        xen_ia64_memmap_info_t *memmap_info;
        unsigned long paddr_start;
        unsigned long paddr_end;
 
-       for (i = *num_mds - 1; i >= 0; i--) {
+       size = sizeof(*memmap_info) +
+               (tables->num_mds + 1) * sizeof(tables->efi_memmap[0]);
+       num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       for (i = tables->num_mds - 1; i >= 0; i--) {
                md = &tables->efi_memmap[i];
                if (md->attribute == EFI_MEMORY_WB &&
                    md->type == EFI_CONVENTIONAL_MEMORY &&
                    md->num_pages >
-                   2 * (1UL << (PAGE_SHIFT - EFI_PAGE_SHIFT))) {
+                   ((num_pages + 1) << (PAGE_SHIFT - EFI_PAGE_SHIFT))) {
                        last_mem_md = md;
                        break;
                }
@@ -186,45 +192,71 @@ setup_dom0_memmap_info(struct domain *d,
        }
        paddr_end = last_mem_md->phys_addr +
            (last_mem_md->num_pages << EFI_PAGE_SHIFT);
-       paddr_start = (paddr_end - PAGE_SIZE) & PAGE_MASK;
-       last_mem_md->num_pages -=
-           (paddr_end - paddr_start) / (1UL << EFI_PAGE_SHIFT);
-
-       md = &tables->efi_memmap[*num_mds];
-       (*num_mds)++;
+       paddr_start = (paddr_end - (num_pages << PAGE_SHIFT)) & PAGE_MASK;
+       last_mem_md->num_pages -= (paddr_end - paddr_start) >> EFI_PAGE_SHIFT;
+
+       md = &tables->efi_memmap[tables->num_mds];
+       tables->num_mds++;
        md->type = EFI_RUNTIME_SERVICES_DATA;
        md->phys_addr = paddr_start;
        md->virt_addr = 0;
-       md->num_pages = 1UL << (PAGE_SHIFT - EFI_PAGE_SHIFT);
+       md->num_pages = num_pages << (PAGE_SHIFT - EFI_PAGE_SHIFT);
        md->attribute = EFI_MEMORY_WB;
 
-       memmap_info = domain_mpa_to_imva(d, md->phys_addr);
-       BUG_ON(*num_mds > NUM_MEM_DESCS);
-
+       BUG_ON(tables->fw_tables_size <
+              sizeof(*tables) +
+              sizeof(tables->efi_memmap[0]) * tables->num_mds);
+       /* with this sort, md doesn't point memmap table */
+       sort(tables->efi_memmap, tables->num_mds,
+            sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);
+
+       memmap_info = domain_mpa_to_imva(d, paddr_start);
        memmap_info->efi_memdesc_size = sizeof(md[0]);
        memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION;
-       memmap_info->efi_memmap_size = *num_mds * sizeof(md[0]);
-       memcpy(&memmap_info->memdesc, &tables->efi_memmap[0],
-              memmap_info->efi_memmap_size);
-       d->shared_info->arch.memmap_info_num_pages = 1;
-       d->shared_info->arch.memmap_info_pfn = md->phys_addr >> PAGE_SHIFT;
-
-       sort(tables->efi_memmap, *num_mds, sizeof(efi_memory_desc_t),
-            efi_mdt_cmp, NULL);
+       memmap_info->efi_memmap_size = tables->num_mds * sizeof(md[0]);
+       dom_fw_copy_to(d,
+                      paddr_start + offsetof(xen_ia64_memmap_info_t, memdesc),
+                      &tables->efi_memmap[0], memmap_info->efi_memmap_size);
+       d->shared_info->arch.memmap_info_num_pages = num_pages;
+       d->shared_info->arch.memmap_info_pfn = paddr_start >> PAGE_SHIFT;
+}
+
+/* setup_guest() @ libxc/xc_linux_build() arranges memory for domU.
+ * however no one arranges memory for dom0,
+ * instead we allocate pages manually.
+ */
+static void
+assign_new_domain0_range(struct domain *d, const efi_memory_desc_t * md)
+{
+       if (md->type == EFI_PAL_CODE ||
+           md->type == EFI_RUNTIME_SERVICES_DATA ||
+           md->type == EFI_CONVENTIONAL_MEMORY) {
+               unsigned long start = md->phys_addr & PAGE_MASK;
+               unsigned long end =
+                       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+               unsigned long addr;
+
+               if (end == start) {
+                       /* md->num_pages = 0 is allowed. */
+                       return;
+               }
+
+               for (addr = start; addr < end; addr += PAGE_SIZE)
+                       assign_new_domain0_page(d, addr);
+       }
 }
 
 /* Complete the dom0 memmap.  */
 int __init
-complete_dom0_memmap(struct domain *d,
-                    struct fw_tables *tables,
-                    unsigned long maxmem, int num_mds)
-{
-       efi_memory_desc_t *md;
+complete_dom0_memmap(struct domain *d, struct fw_tables *tables)
+{
        u64 addr;
        void *efi_map_start, *efi_map_end, *p;
        u64 efi_desc_size;
        int i;
-       unsigned long dom_mem = maxmem - (d->tot_pages << PAGE_SHIFT);
+
+       for (i = 0; i < tables->num_mds; i++)
+               assign_new_domain0_range(d, &tables->efi_memmap[i]);
 
        /* Walk through all MDT entries.
           Copy all interesting entries.  */
@@ -234,7 +266,7 @@ complete_dom0_memmap(struct domain *d,
 
        for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
                const efi_memory_desc_t *md = p;
-               efi_memory_desc_t *dom_md = &tables->efi_memmap[num_mds];
+               efi_memory_desc_t *dom_md = 
&tables->efi_memmap[tables->num_mds];
                u64 start = md->phys_addr;
                u64 size = md->num_pages << EFI_PAGE_SHIFT;
                u64 end = start + size;
@@ -267,7 +299,7 @@ complete_dom0_memmap(struct domain *d,
                        /* Copy descriptor.  */
                        *dom_md = *md;
                        dom_md->virt_addr = 0;
-                       num_mds++;
+                       tables->num_mds++;
                        break;
 
                case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
@@ -288,31 +320,55 @@ complete_dom0_memmap(struct domain *d,
                        *dom_md = *md;
                        dom_md->phys_addr = mpaddr;
                        dom_md->virt_addr = 0;
-                       num_mds++;
+                       tables->num_mds++;
                        break;
 
                case EFI_CONVENTIONAL_MEMORY:
                case EFI_LOADER_CODE:
                case EFI_LOADER_DATA:
                case EFI_BOOT_SERVICES_CODE:
-               case EFI_BOOT_SERVICES_DATA:
+               case EFI_BOOT_SERVICES_DATA: {
+                       u64 dom_md_start;
+                       u64 dom_md_end;
+                       unsigned long left_mem =
+                               (unsigned long)(d->max_pages - d->tot_pages) <<
+                               PAGE_SHIFT;
+
                        if (!(md->attribute & EFI_MEMORY_WB))
                                break;
 
-                       start = max(FW_END_PADDR, start);
-                       end = min(start + dom_mem, end);
-                       if (end <= start)
-                               break;
-
-                       dom_md->type = EFI_CONVENTIONAL_MEMORY;
-                       dom_md->phys_addr = start;
-                       dom_md->virt_addr = 0;
-                       dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
-                       dom_md->attribute = EFI_MEMORY_WB;
-                       num_mds++;
-
-                       dom_mem -= dom_md->num_pages << EFI_PAGE_SHIFT;
-                       break;
+                       dom_md_start = max(tables->fw_end_paddr, start);
+                       dom_md_end = dom_md_start;
+                       do {
+                               dom_md_end = min(dom_md_end + left_mem, end);
+                               if (dom_md_end < dom_md_start + PAGE_SIZE)
+                                       break;
+
+                               dom_md->type = EFI_CONVENTIONAL_MEMORY;
+                               dom_md->phys_addr = dom_md_start;
+                               dom_md->virt_addr = 0;
+                               dom_md->num_pages =
+                                       (dom_md_end - dom_md_start) >>
+                                       EFI_PAGE_SHIFT;
+                               dom_md->attribute = EFI_MEMORY_WB;
+
+                               assign_new_domain0_range(d, dom_md);
+                               /*
+                                * recalculate left_mem.
+                                * we might already allocated memory in
+                                * this region because of kernel loader.
+                                * So we might consumed less than
+                                * (dom_md_end - dom_md_start) above.
+                                */
+                               left_mem = (unsigned long)
+                                       (d->max_pages - d->tot_pages) <<
+                                       PAGE_SHIFT;
+                       } while (left_mem > 0 && dom_md_end < end);
+
+                       if (!(dom_md_end < dom_md_start + PAGE_SIZE))
+                               tables->num_mds++;
+                       break;
+               }
 
                case EFI_UNUSABLE_MEMORY:
                case EFI_PAL_CODE:
@@ -326,7 +382,7 @@ complete_dom0_memmap(struct domain *d,
                        dom_md->virt_addr = 0;
                        dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
                        dom_md->attribute = EFI_MEMORY_WB;
-                       num_mds++;
+                       tables->num_mds++;
                        break;
 
                default:
@@ -335,34 +391,13 @@ complete_dom0_memmap(struct domain *d,
                               "unhandled MDT entry type %u\n", md->type);
                }
        }
-       BUG_ON(num_mds > NUM_MEM_DESCS);
-
-       sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t),
+       BUG_ON(tables->fw_tables_size <
+              sizeof(*tables) +
+              sizeof(tables->efi_memmap[0]) * tables->num_mds);
+
+       sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t),
             efi_mdt_cmp, NULL);
 
-       /* setup_guest() @ libxc/xc_linux_build() arranges memory for domU.
-        * however no one arranges memory for dom0,
-        * instead we allocate pages manually.
-        */
-       for (i = 0; i < num_mds; i++) {
-               md = &tables->efi_memmap[i];
-
-               if (md->type == EFI_LOADER_DATA ||
-                   md->type == EFI_PAL_CODE ||
-                   md->type == EFI_CONVENTIONAL_MEMORY) {
-                       unsigned long start = md->phys_addr & PAGE_MASK;
-                       unsigned long end = md->phys_addr +
-                           (md->num_pages << EFI_PAGE_SHIFT);
-
-                       if (end == start) {
-                               /* md->num_pages = 0 is allowed. */
-                               continue;
-                       }
-
-                       for (addr = start; addr < end; addr += PAGE_SIZE)
-                               assign_new_domain0_page(d, addr);
-               }
-       }
        // Map low-memory holes & unmapped MMIO for legacy drivers
        for (addr = 0; addr < ONE_MB; addr += PAGE_SIZE) {
                if (domain_page_mapped(d, addr))
@@ -375,8 +410,8 @@ complete_dom0_memmap(struct domain *d,
                                                flags);
                }
        }
-       setup_dom0_memmap_info(d, tables, &num_mds);
-       return num_mds;
+       setup_dom0_memmap_info(d, tables);
+       return tables->num_mds;
 }
 
 /*
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/arch/ia64/xen/dom_fw_domu.c
--- a/xen/arch/ia64/xen/dom_fw_domu.c   Thu May 31 14:47:08 2007 -0600
+++ b/xen/arch/ia64/xen/dom_fw_domu.c   Mon Jun 04 13:57:08 2007 -0600
@@ -61,19 +61,14 @@ void efi_systable_init_domu(struct fw_ta
        BUG_ON(i > NUM_EFI_SYS_TABLES);
 }
 
-#define MAKE_MD(typ, attr, start, end) \
-       xen_ia64_efi_make_md((tables), &(i), (typ), (attr), (start), (end))
-
 int
 complete_domu_memmap(domain_t * d,
                     struct fw_tables *tables,
                     unsigned long maxmem,
-                    int num_mds,
                     unsigned long memmap_info_pfn,
                     unsigned long memmap_info_num_pages)
 {
        efi_memory_desc_t *md;
-       int i = num_mds;        /* for MAKE_MD */
        int create_memmap = 0;
        xen_ia64_memmap_info_t *memmap_info;
        unsigned long memmap_info_size;
@@ -142,12 +137,12 @@ complete_domu_memmap(domain_t * d,
                memmap_info->efi_memmap_size = 1 * sizeof(md[0]);
 
                md = (efi_memory_desc_t *) & memmap_info->memdesc;
-               md[num_mds].type = EFI_CONVENTIONAL_MEMORY;
-               md[num_mds].pad = 0;
-               md[num_mds].phys_addr = 0;
-               md[num_mds].virt_addr = 0;
-               md[num_mds].num_pages = maxmem >> EFI_PAGE_SHIFT;
-               md[num_mds].attribute = EFI_MEMORY_WB;
+               md->type = EFI_CONVENTIONAL_MEMORY;
+               md->pad = 0;
+               md->phys_addr = 0;
+               md->virt_addr = 0;
+               md->num_pages = maxmem >> EFI_PAGE_SHIFT;
+               md->attribute = EFI_MEMORY_WB;
        }
 
        memmap_start = &memmap_info->memdesc;
@@ -175,43 +170,61 @@ complete_domu_memmap(domain_t * d,
                start = md->phys_addr;
                end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
 
-               if (start < FW_END_PADDR)
-                       start = FW_END_PADDR;
+               if (start < tables->fw_end_paddr)
+                       start = tables->fw_end_paddr;
                if (end <= start)
                        continue;
 
                /* exclude [paddr_start, paddr_end) */
                if (paddr_end <= start || end <= paddr_start) {
-                       MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start,
-                               end);
+                       xen_ia64_efi_make_md(&tables->
+                                            efi_memmap[tables->num_mds],
+                                            EFI_CONVENTIONAL_MEMORY,
+                                            EFI_MEMORY_WB, start, end);
+                       tables->num_mds++;
                } else if (paddr_start <= start && paddr_end < end) {
-                       MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB,
-                               paddr_end, end);
+                       xen_ia64_efi_make_md(&tables->
+                                            efi_memmap[tables->num_mds],
+                                            EFI_CONVENTIONAL_MEMORY,
+                                            EFI_MEMORY_WB, paddr_end, end);
+                       tables->num_mds++;
                } else if (start < paddr_start && end <= paddr_end) {
-                       MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start,
-                               paddr_start);
+                       xen_ia64_efi_make_md(&tables->
+                                            efi_memmap[tables->num_mds],
+                                            EFI_CONVENTIONAL_MEMORY,
+                                            EFI_MEMORY_WB, start, paddr_start);
+                       tables->num_mds++;
                } else {
-                       MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start,
-                               paddr_start);
-                       MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB,
-                               paddr_end, end);
+                       xen_ia64_efi_make_md(&tables->
+                                            efi_memmap[tables->num_mds],
+                                            EFI_CONVENTIONAL_MEMORY,
+                                            EFI_MEMORY_WB, start, paddr_start);
+                       tables->num_mds++;
+                       xen_ia64_efi_make_md(&tables->
+                                            efi_memmap[tables->num_mds],
+                                            EFI_CONVENTIONAL_MEMORY,
+                                            EFI_MEMORY_WB, paddr_end, end);
+                       tables->num_mds++;
                }
        }
 
        /* memmap info page. */
-       MAKE_MD(EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB, paddr_start,
-               paddr_end);
+       xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds],
+                            EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB,
+                            paddr_start, paddr_end);
+       tables->num_mds++;
 
        /* Create an entry for IO ports.  */
-       MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC,
-               IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE);
-
-       num_mds = i;
-       sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t),
+       xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds],
+                            EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC,
+                            IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE);
+       tables->num_mds++;
+
+       sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t),
             efi_mdt_cmp, NULL);
 
        xen_ia64_dom_fw_unmap(d, memmap_info);
-       return num_mds;
+       return tables->num_mds;
 }
 
 /*
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/arch/ia64/xen/dom_fw_utils.c
--- a/xen/arch/ia64/xen/dom_fw_utils.c  Thu May 31 14:47:08 2007 -0600
+++ b/xen/arch/ia64/xen/dom_fw_utils.c  Mon Jun 04 13:57:08 2007 -0600
@@ -27,6 +27,7 @@
 #include <asm/fpswa.h>
 #include <asm/dom_fw.h>
 #include <asm/dom_fw_common.h>
+#include <asm/dom_fw_utils.h>
 
 #include <linux/sort.h>
 
@@ -70,6 +71,8 @@ static void dom_fw_domain_init(struct do
 
 static int dom_fw_set_convmem_end(struct domain *d)
 {
+       unsigned long gpaddr;
+       size_t size;
        xen_ia64_memmap_info_t *memmap_info;
        efi_memory_desc_t *md;
        void *p;
@@ -79,26 +82,23 @@ static int dom_fw_set_convmem_end(struct
        if (d->shared_info->arch.memmap_info_pfn == 0)
                return -EINVAL;
 
-       memmap_info =
-           domain_mpa_to_imva(d,
-                              d->shared_info->arch.
-                              memmap_info_pfn << PAGE_SHIFT);
-       if (memmap_info->efi_memmap_size == 0
-           || memmap_info->efi_memdesc_size != sizeof(*md)
-           || memmap_info->efi_memdesc_version !=
-           EFI_MEMORY_DESCRIPTOR_VERSION)
+       gpaddr = d->shared_info->arch.memmap_info_pfn << PAGE_SHIFT;
+       size = d->shared_info->arch.memmap_info_num_pages << PAGE_SHIFT;
+       memmap_info = _xmalloc(size, __alignof__(*memmap_info));
+       if (memmap_info == NULL)
+               return -ENOMEM;
+       dom_fw_copy_from(memmap_info, d, gpaddr, size);
+       if (memmap_info->efi_memmap_size == 0 ||
+           memmap_info->efi_memdesc_size != sizeof(*md) ||
+           memmap_info->efi_memdesc_version != EFI_MEMORY_DESCRIPTOR_VERSION ||
+           sizeof(*memmap_info) + memmap_info->efi_memmap_size > size ||
+           memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size == 0) {
+               xfree(memmap_info);
                return -EINVAL;
-
-       /* only 1page case is supported */
-       if (d->shared_info->arch.memmap_info_num_pages != 1)
-               return -ENOSYS;
+       }
 
        memmap_start = &memmap_info->memdesc;
        memmap_end = memmap_start + memmap_info->efi_memmap_size;
-
-       /* XXX Currently the table must be in a single page. */
-       if ((unsigned long)memmap_end > (unsigned long)memmap_info + PAGE_SIZE)
-               return -EINVAL;
 
        /* sort it bofore use
         * XXX: this is created by user space domain builder so that
@@ -122,6 +122,9 @@ static int dom_fw_set_convmem_end(struct
                    md->num_pages > 0 && d->arch.convmem_end < end)
                        d->arch.convmem_end = end;
        }
+
+       dom_fw_copy_to(d, gpaddr, memmap_info, size);
+       xfree(memmap_info);
        return 0;
 }
 
@@ -135,22 +138,62 @@ assign_new_domain_page_if_dom0(struct do
                assign_new_domain0_page(d, mpaddr);
 }
 
-static void
-dom_fw_setup_for_domain_restore(domain_t *d, unsigned long maxmem)
+static void dom_fw_setup_for_domain_restore(domain_t * d, unsigned long maxmem)
 {
        assign_new_domain_page(d, FW_HYPERCALL_BASE_PADDR);
        dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR));
        d->arch.convmem_end = maxmem;
 }
 
+/* copy memory range to domain pseudo physical address space */
+void
+dom_fw_copy_to(struct domain *d, unsigned long dest_gpaddr,
+              void *src, size_t size)
+{
+       while (size > 0) {
+               unsigned long page_offset = dest_gpaddr & ~PAGE_MASK;
+               size_t copy_size = size;
+               void *dest;
+
+               if (page_offset + copy_size > PAGE_SIZE)
+                       copy_size = PAGE_SIZE - page_offset;
+               dest = domain_mpa_to_imva(d, dest_gpaddr);
+               memcpy(dest, src, copy_size);
+
+               src += copy_size;
+               dest_gpaddr += copy_size;
+               size -= copy_size;
+       }
+}
+
+/* copy memory range from domain pseudo physical address space */
+void
+dom_fw_copy_from(void *dest, struct domain *d, unsigned long src_gpaddr,
+                size_t size)
+{
+       while (size > 0) {
+               unsigned long page_offset = src_gpaddr & ~PAGE_MASK;
+               size_t copy_size = size;
+               void *src;
+
+               if (page_offset + copy_size > PAGE_SIZE)
+                       copy_size = PAGE_SIZE - page_offset;
+               src = domain_mpa_to_imva(d, src_gpaddr);
+               memcpy(dest, src, copy_size);
+
+               dest += copy_size;
+               src_gpaddr += copy_size;
+               size -= copy_size;
+       }
+}
+
 int dom_fw_setup(domain_t * d, unsigned long bp_mpa, unsigned long maxmem)
 {
        int old_domu_builder = 0;
        struct xen_ia64_boot_param *bp;
-       struct fw_tables *imva_tables_base;
 
        BUILD_BUG_ON(sizeof(struct fw_tables) >
-                    (FW_TABLES_END_PADDR - FW_TABLES_BASE_PADDR));
+                    (FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR));
 
        if (bp_mpa == 0) {
                /* bp_mpa == 0 means this is domain restore case. */
@@ -190,10 +233,6 @@ int dom_fw_setup(domain_t * d, unsigned 
                }
        }
 
-       /* Create page for FW tables.  */
-       assign_new_domain_page_if_dom0(d, FW_TABLES_BASE_PADDR);
-       imva_tables_base = (struct fw_tables *)domain_mpa_to_imva
-           (d, FW_TABLES_BASE_PADDR);
        /* Create page for acpi tables.  */
        if (d != dom0 && old_domu_builder) {
                struct fake_acpi_tables *imva;
@@ -203,20 +242,81 @@ int dom_fw_setup(domain_t * d, unsigned 
        if (d == dom0 || old_domu_builder) {
                int ret;
                unsigned long imva_hypercall_base;
+               size_t fw_tables_size;
+               struct fw_tables *fw_tables;
+               unsigned long gpaddr;
 
                /* Create page for hypercalls.  */
                assign_new_domain_page_if_dom0(d, FW_HYPERCALL_BASE_PADDR);
                imva_hypercall_base = (unsigned long)domain_mpa_to_imva
                    (d, FW_HYPERCALL_BASE_PADDR);
 
+               /* Estimate necessary efi memmap size and allocate memory */
+               fw_tables_size = sizeof(*fw_tables) +
+                       (ia64_boot_param->efi_memmap_size /
+                        ia64_boot_param->efi_memdesc_size + NUM_MEM_DESCS) *
+                       sizeof(fw_tables->efi_memmap[0]);
+               if (fw_tables_size <
+                   FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR)
+                       fw_tables_size =
+                           FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR;
+               fw_tables_size = (fw_tables_size + ((1UL << EFI_PAGE_SHIFT) - 
1))
+                       & ~((1UL << EFI_PAGE_SHIFT) - 1);
+               fw_tables =
+                   (struct fw_tables *)_xmalloc(fw_tables_size,
+                                                __alignof__(*fw_tables));
+               if (fw_tables == NULL) {
+                       dprintk(XENLOG_INFO,
+                               "can't allocate fw_tables memory size = %ld\n",
+                               fw_tables_size);
+                       return -ENOMEM;
+               }
+               memset(fw_tables, 0, fw_tables_size);
+               BUILD_BUG_ON(FW_END_PADDR_MIN != FW_TABLES_END_PADDR_MIN);
+               fw_tables->fw_tables_size = fw_tables_size;
+               fw_tables->fw_end_paddr = FW_TABLES_BASE_PADDR + fw_tables_size;
+               fw_tables->fw_tables_end_paddr =
+                       FW_TABLES_BASE_PADDR + fw_tables_size;
+               fw_tables->num_mds = 0;
+
+               /* It is necessary to allocate pages before dom_fw_init()
+                * dom_fw_init() uses up page to d->max_pages.
+                */
+               for (gpaddr = FW_TABLES_BASE_PADDR;
+                    gpaddr < fw_tables->fw_end_paddr; gpaddr += PAGE_SIZE)
+                       assign_new_domain_page_if_dom0(d, gpaddr);
+
                ret = dom_fw_init(d, d->arch.breakimm, bp,
-                                 imva_tables_base, imva_hypercall_base,
-                                 maxmem);
-               if (ret < 0)
+                                 fw_tables, imva_hypercall_base, maxmem);
+               if (ret < 0) {
+                       xfree(fw_tables);
                        return ret;
-       }
-
-       dom_fw_domain_init(d, imva_tables_base);
+               }
+               if (sizeof(*fw_tables) +
+                   fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]) >
+                   fw_tables_size) {
+                       panic("EFI memmap too large. Increase NUM_MEM_DESCS.\n"
+                             "fw_table_size %ld > %ld num_mds %ld "
+                             "NUM_MEM_DESCS %d.\n",
+                             fw_tables_size, fw_tables->fw_tables_size,
+                             fw_tables->num_mds, NUM_MEM_DESCS);
+               }
+               fw_tables_size = sizeof(*fw_tables) +
+                       fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]);
+
+               /* clear domain builder internal use member */
+               fw_tables->fw_tables_size = 0;
+               fw_tables->fw_end_paddr = 0;
+               fw_tables->fw_tables_end_paddr = 0;
+               fw_tables->num_mds = 0;
+
+               /* copy fw_tables into domain pseudo physical address space */
+               dom_fw_copy_to(d, FW_TABLES_BASE_PADDR, fw_tables,
+                              fw_tables_size);
+               xfree(fw_tables);
+       }
+
+       dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR));
        return dom_fw_set_convmem_end(d);
 }
 
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/include/asm-ia64/dom_fw.h
--- a/xen/include/asm-ia64/dom_fw.h     Thu May 31 14:47:08 2007 -0600
+++ b/xen/include/asm-ia64/dom_fw.h     Mon Jun 04 13:57:08 2007 -0600
@@ -8,7 +8,8 @@
 /* Portion of guest physical memory space reserved for PAL/SAL/EFI/ACPI
    data and code.  */
 #define FW_BASE_PADDR          0x0000UL
-#define FW_END_PADDR           0x3000UL
+/* It is assumed that FW_END_PADDR_MIN = FW_TABLES_END_PADDR_MIN */
+#define FW_END_PADDR_MIN       0x3000UL
 
 /* This is used to determined the portion of a domain's metaphysical memory
    space reserved for the hypercall patch table. */
@@ -29,7 +30,7 @@
 
 /* Base and end guest physical address of EFI and SAL (non-ACPI) tables.  */
 #define FW_TABLES_BASE_PADDR   0x2000UL
-#define FW_TABLES_END_PADDR    0x3000UL
+#define FW_TABLES_END_PADDR_MIN        0x3000UL
 
 
 /* Hypercalls number have a low part and a high part.
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/include/asm-ia64/dom_fw_common.h
--- a/xen/include/asm-ia64/dom_fw_common.h      Thu May 31 14:47:08 2007 -0600
+++ b/xen/include/asm-ia64/dom_fw_common.h      Mon Jun 04 13:57:08 2007 -0600
@@ -64,16 +64,26 @@ struct fw_tables {
     /* End of SAL descriptors.  Do not forget to update checkum bound.  */
 
     fpswa_interface_t                   fpswa_inf;
-    efi_memory_desc_t                   efi_memmap[NUM_MEM_DESCS];
     unsigned long                       func_ptrs[2*NFUNCPTRS];
     struct xen_sal_data                 sal_data;
     unsigned char                       fw_vendor[sizeof(FW_VENDOR)];
+
+    /*
+     * These four member for domain builder internal use at virtualized
+     * efi memmap creation. They should be zero-cleared after use.
+     */
+    unsigned long                       fw_tables_size;
+    unsigned long                       fw_end_paddr;   
+    unsigned long                       fw_tables_end_paddr;
+    unsigned long                       num_mds;
+
+    efi_memory_desc_t                   efi_memmap[0];
 };
 #define FW_FIELD_MPA(field)                                     \
     FW_TABLES_BASE_PADDR + offsetof(struct fw_tables, field)
 
 void
-xen_ia64_efi_make_md(struct fw_tables *tables, int *index,
+xen_ia64_efi_make_md(efi_memory_desc_t *md,
                      uint32_t type, uint64_t attr, 
                      uint64_t start, uint64_t end);
 uint8_t generate_acpi_checksum(void *tbl, unsigned long len);
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/include/asm-ia64/dom_fw_dom0.h
--- a/xen/include/asm-ia64/dom_fw_dom0.h        Thu May 31 14:47:08 2007 -0600
+++ b/xen/include/asm-ia64/dom_fw_dom0.h        Mon Jun 04 13:57:08 2007 -0600
@@ -25,11 +25,7 @@ struct domain;
 struct domain;
 
 void efi_systable_init_dom0(struct fw_tables *tables);
-int
-complete_dom0_memmap(struct domain *d,
-                     struct fw_tables *tables,
-                     unsigned long maxmem,
-                     int num_mds);
+int complete_dom0_memmap(struct domain *d, struct fw_tables *tables);
 
 #endif /* __ASM_IA64_DOM_FW_DOM0_H__ */
 /*
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/include/asm-ia64/dom_fw_domu.h
--- a/xen/include/asm-ia64/dom_fw_domu.h        Thu May 31 14:47:08 2007 -0600
+++ b/xen/include/asm-ia64/dom_fw_domu.h        Mon Jun 04 13:57:08 2007 -0600
@@ -29,9 +29,9 @@ complete_domu_memmap(domain_t *d,
 complete_domu_memmap(domain_t *d,
                      struct fw_tables *tables,
                      unsigned long maxmem,
-                     int num_mds,
                      unsigned long memmap_info_pfn,
                      unsigned long reserved_size);
+
 #endif /* __ASM_IA64_DOM_FW_DOMU_H__ */
 /*
  * Local variables:
diff -r b46c2ff6dfb0 -r c0cdcebc0377 xen/include/asm-ia64/dom_fw_utils.h
--- a/xen/include/asm-ia64/dom_fw_utils.h       Thu May 31 14:47:08 2007 -0600
+++ b/xen/include/asm-ia64/dom_fw_utils.h       Mon Jun 04 13:57:08 2007 -0600
@@ -26,6 +26,10 @@ int xen_ia64_is_vcpu_allocated(struct do
 int xen_ia64_is_vcpu_allocated(struct domain *d, uint32_t vcpu); 
 int xen_ia64_is_running_on_sim(struct domain *unused);
 int xen_ia64_is_dom0(struct domain *d);
+void dom_fw_copy_to(struct domain *d, unsigned long dest_gpaddr,
+                    void *src, size_t size); 
+void dom_fw_copy_from(void* dest, struct domain *d, unsigned long src_gpaddr,
+                      size_t size); 
 
 #endif /* __ASM_XEN_IA64_DOM_FW_UTILS_H__ */
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.