# 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
|