# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1180744692 -32400 # Node ID de2f7b41a3ba26b6842259e165b71c0cd73a1197 # Parent b46c2ff6dfb0de75e17fee01f0adc4d35d5e8322 allow dynamic allocation of dom0 fw_tables PATCHNAME: allow_dynamic_allocation_of_dom0_fw_tables Signed-off-by: Isaku Yamahata diff -r b46c2ff6dfb0 -r de2f7b41a3ba 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 Sat Jun 02 09:38:12 2007 +0900 @@ -18,6 +18,7 @@ * */ +#include #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,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 *) @@ -150,14 +158,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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 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) ({assert(0);0;}) #endif /* XC_IA64_DOM_IA64_UTIL_H */ diff -r b46c2ff6dfb0 -r de2f7b41a3ba 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 Sat Jun 02 09:38:12 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 { \ @@ -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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 2007 +0900 @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -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,8 @@ 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 +300,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 +321,56 @@ 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 +384,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 +393,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 +412,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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 2007 +0900 @@ -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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 2007 +0900 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -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,83 @@ 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 for it */ + 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("too large efi memmap. 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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 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 b46c2ff6dfb0 -r de2f7b41a3ba 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 Sat Jun 02 09:38:12 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 b46c2ff6dfb0 -r de2f7b41a3ba 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 Sat Jun 02 09:38:12 2007 +0900 @@ -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 de2f7b41a3ba 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 Sat Jun 02 09:38:12 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 b46c2ff6dfb0 -r de2f7b41a3ba 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 Sat Jun 02 09:38:12 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__ */