# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1179394070 -32400 # Node ID e0b79876c1ecd2b52a662d92925224c8653f5e3d # Parent a3f0df05cd3258cb215eafdd6a3c1eb0928742e0 allow huge size efi memory map of real machine. PATCHNAME: allow_dynamic_allocation_of_dom0_fw_tables Signed-off-by: Isaku Yamahata diff -r a3f0df05cd32 -r e0b79876c1ec tools/libxc/ia64/xc_dom_ia64_util.c --- a/tools/libxc/ia64/xc_dom_ia64_util.c Thu May 17 19:11:11 2007 +0900 +++ b/tools/libxc/ia64/xc_dom_ia64_util.c Thu May 17 18:27:50 2007 +0900 @@ -18,6 +18,7 @@ * */ +#include #include "xg_private.h" #include "xc_dom.h" #include "asm/dom_fw.h" @@ -113,12 +114,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); @@ -128,11 +129,18 @@ 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 *) @@ -149,13 +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 a3f0df05cd32 -r e0b79876c1ec tools/libxc/ia64/xc_dom_ia64_util.h --- a/tools/libxc/ia64/xc_dom_ia64_util.h Thu May 17 19:11:11 2007 +0900 +++ b/tools/libxc/ia64/xc_dom_ia64_util.h Thu May 17 18:27:50 2007 +0900 @@ -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, maxmem) ({assert(0);0;}) #endif /* XC_IA64_DOM_IA64_UTIL_H */ diff -r a3f0df05cd32 -r e0b79876c1ec xen/arch/ia64/xen/dom_fw_common.c --- a/xen/arch/ia64/xen/dom_fw_common.c Thu May 17 19:11:11 2007 +0900 +++ b/xen/arch/ia64/xen/dom_fw_common.c Thu May 17 18:27:50 2007 +0900 @@ -35,22 +35,17 @@ #include 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 { \ @@ -420,7 +415,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, } else fpswa_supported = 0; - 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, maxmem); } 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 a3f0df05cd32 -r e0b79876c1ec xen/arch/ia64/xen/dom_fw_dom0.c --- a/xen/arch/ia64/xen/dom_fw_dom0.c Thu May 17 19:11:11 2007 +0900 +++ b/xen/arch/ia64/xen/dom_fw_dom0.c Thu May 17 18:27:50 2007 +0900 @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -158,21 +159,25 @@ efi_systable_init_dom0(struct fw_tables } 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; + unsigned long 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_SIZE; + 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))) { + md->num_pages > (num_pages + 1) * (1UL << (PAGE_SHIFT - EFI_PAGE_SHIFT))) { last_mem_md = md; break; } @@ -186,30 +191,32 @@ 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; + paddr_start = (paddr_end - (num_pages << PAGE_SHIFT)) & PAGE_MASK; last_mem_md->num_pages -= (paddr_end - paddr_start) / (1UL << EFI_PAGE_SHIFT); - md = &tables->efi_memmap[*num_mds]; - (*num_mds)++; + 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); 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; + memmap_info->efi_memmap_size = tables->num_mds * sizeof(md[0]); + dom_fw_copy_to(d, + md->phys_addr + 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 = md->phys_addr >> PAGE_SHIFT; - sort(tables->efi_memmap, *num_mds, sizeof(efi_memory_desc_t), + sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL); } @@ -217,8 +224,7 @@ int __init int __init complete_dom0_memmap(struct domain *d, struct fw_tables *tables, - unsigned long maxmem, - int num_mds) + unsigned long maxmem) { efi_memory_desc_t *md; u64 addr; @@ -235,7 +241,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; @@ -268,7 +274,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: @@ -289,7 +295,7 @@ 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: @@ -300,7 +306,7 @@ complete_dom0_memmap(struct domain *d, if (!(md->attribute & EFI_MEMORY_WB)) break; - start = max(FW_END_PADDR, start); + start = max(tables->fw_end_paddr, start); end = min(start + dom_mem, end); if (end <= start) break; @@ -310,7 +316,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++; dom_mem -= dom_md->num_pages << EFI_PAGE_SHIFT; break; @@ -327,7 +333,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: @@ -336,16 +342,17 @@ complete_dom0_memmap(struct domain *d, "unhandled MDT entry type %u\n", md->type); } } - BUG_ON(num_mds > NUM_MEM_DESCS); + BUG_ON(tables->fw_tables_size < + sizeof(*tables) + sizeof(tables->efi_memmap[0]) * tables->num_mds); - sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t), + 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++) { + for (i = 0; i < tables->num_mds; i++) { md = &tables->efi_memmap[i]; if (md->type == EFI_LOADER_DATA || @@ -376,8 +383,8 @@ complete_dom0_memmap(struct domain *d, PAGE_SIZE, flags); } } - setup_dom0_memmap_info(d, tables, &num_mds); - return num_mds; + setup_dom0_memmap_info(d, tables); + return tables->num_mds; } /* diff -r a3f0df05cd32 -r e0b79876c1ec xen/arch/ia64/xen/dom_fw_domu.c --- a/xen/arch/ia64/xen/dom_fw_domu.c Thu May 17 19:11:11 2007 +0900 +++ b/xen/arch/ia64/xen/dom_fw_domu.c Thu May 17 18:27:50 2007 +0900 @@ -61,19 +61,14 @@ efi_systable_init_domu(struct fw_tables 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; @@ -140,12 +135,12 @@ complete_domu_memmap(domain_t *d, EFI_MEMORY_DESCRIPTOR_VERSION; 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; @@ -171,43 +166,56 @@ 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 a3f0df05cd32 -r e0b79876c1ec xen/arch/ia64/xen/dom_fw_utils.c --- a/xen/arch/ia64/xen/dom_fw_utils.c Thu May 17 19:11:11 2007 +0900 +++ b/xen/arch/ia64/xen/dom_fw_utils.c Thu May 17 18:27:50 2007 +0900 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -75,6 +76,8 @@ static int static int dom_fw_set_convmem_end(struct domain *d) { + unsigned long gpaddr; + unsigned long size; xen_ia64_memmap_info_t* memmap_info; efi_memory_desc_t *md; void *p; @@ -84,22 +87,22 @@ dom_fw_set_convmem_end(struct domain *d) 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); + gpaddr = d->shared_info->arch.memmap_info_pfn << PAGE_SHIFT; + size = d->shared_info->arch.memmap_info_num_pages << PAGE_SHIFT; + memmap_info = xmalloc_bytes(size); + 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) + EFI_MEMORY_DESCRIPTOR_VERSION) { + 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 @@ -121,6 +124,9 @@ dom_fw_set_convmem_end(struct domain *d) d->arch.convmem_end < end) d->arch.convmem_end = end; } + + dom_fw_copy_to(d, gpaddr, memmap_info, size); + xfree(memmap_info); return 0; } @@ -134,15 +140,56 @@ assign_new_domain_page_if_dom0(struct do assign_new_domain0_page(d, mpaddr); } +/* 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_SIZE; + unsigned int 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_SIZE; + unsigned int 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)); /* Create page for boot_param. */ assign_new_domain_page_if_dom0(d, bp_mpa); @@ -175,10 +222,6 @@ dom_fw_setup(domain_t *d, unsigned long } } - /* 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; @@ -188,19 +231,72 @@ dom_fw_setup(domain_t *d, unsigned long if (d == dom0 || old_domu_builder) { int ret; unsigned long imva_hypercall_base; + unsigned int 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 for it */ + fw_tables_size = sizeof(*fw_tables) + + NUM_MEM_DESCS * sizeof(fw_tables->efi_memmap[0]) + + ia64_boot_param->efi_memdesc_size; + 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_bytes(fw_tables_size); + if (fw_tables == NULL) { + dprintk(XENLOG_INFO, + "can't allocate fw_tables memory size = %d\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; + 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("too large efi memmap. increase NUM_MEM_DESCS.\n" + "fw_table_size %d > %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 */ + for (gpaddr = FW_TABLES_BASE_PADDR; + gpaddr < fw_tables->fw_end_paddr; + gpaddr += PAGE_SIZE) + assign_new_domain_page_if_dom0(d, gpaddr); + + 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 a3f0df05cd32 -r e0b79876c1ec xen/include/asm-ia64/dom_fw.h --- a/xen/include/asm-ia64/dom_fw.h Thu May 17 19:11:11 2007 +0900 +++ b/xen/include/asm-ia64/dom_fw.h Thu May 17 18:27:50 2007 +0900 @@ -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 a3f0df05cd32 -r e0b79876c1ec xen/include/asm-ia64/dom_fw_common.h --- a/xen/include/asm-ia64/dom_fw_common.h Thu May 17 19:11:11 2007 +0900 +++ b/xen/include/asm-ia64/dom_fw_common.h Thu May 17 18:27:50 2007 +0900 @@ -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 a3f0df05cd32 -r e0b79876c1ec xen/include/asm-ia64/dom_fw_dom0.h --- a/xen/include/asm-ia64/dom_fw_dom0.h Thu May 17 19:11:11 2007 +0900 +++ b/xen/include/asm-ia64/dom_fw_dom0.h Thu May 17 18:27:50 2007 +0900 @@ -28,8 +28,7 @@ int int complete_dom0_memmap(struct domain *d, struct fw_tables *tables, - unsigned long maxmem, - int num_mds); + unsigned long maxmem); #endif /* __ASM_IA64_DOM_FW_DOM0_H__ */ /* diff -r a3f0df05cd32 -r e0b79876c1ec xen/include/asm-ia64/dom_fw_domu.h --- a/xen/include/asm-ia64/dom_fw_domu.h Thu May 17 19:11:11 2007 +0900 +++ b/xen/include/asm-ia64/dom_fw_domu.h Thu May 17 18:27:50 2007 +0900 @@ -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 a3f0df05cd32 -r e0b79876c1ec xen/include/asm-ia64/dom_fw_utils.h --- a/xen/include/asm-ia64/dom_fw_utils.h Thu May 17 19:11:11 2007 +0900 +++ b/xen/include/asm-ia64/dom_fw_utils.h Thu May 17 18:27:50 2007 +0900 @@ -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__ */