diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 27b60551f8..c0b0568811 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -3,6 +3,7 @@ */ #include "xg_private.h" +#include "xc_private.h" #include #if defined(__i386__) @@ -32,6 +33,8 @@ #define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) #endif +#define NR_GRANT_FRAMES 4 + #ifdef __ia64__ #define get_tot_pages xc_get_max_pages #else @@ -504,6 +507,8 @@ static int setup_guest(int xc_handle, goto error_out; } + shadow_mode_enabled = !!strstr(dsi.xen_guest_string, + "SHADOW=translate"); /* * Why do we need this? The number of page-table frames depends on the * size of the bootstrap address space. But the size of the address space @@ -587,7 +592,7 @@ static int setup_guest(int xc_handle, goto error_out; } - if ( (page_array = malloc((nr_pages + 1) * sizeof(unsigned long))) == NULL ) + if ( (page_array = malloc((nr_pages + 1 + NR_GRANT_FRAMES) * sizeof(unsigned long))) == NULL ) { PERROR("Could not allocate memory"); goto error_out; @@ -622,19 +627,23 @@ static int setup_guest(int xc_handle, if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL ) goto error_out; - shadow_mode_enabled = !!strstr(dsi.xen_guest_string, - "SHADOW=translate"); - /* Write the phys->machine and machine->phys table entries. */ physmap_pfn = (vphysmap_start - dsi.v_start) >> PAGE_SHIFT; physmap = physmap_e = xc_map_foreign_range( xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[physmap_pfn++]); - if (shadow_mode_enabled) - page_array[nr_pages] = shared_info_frame; + page_array[nr_pages] = shared_info_frame; - for ( count = 0; count < nr_pages + shadow_mode_enabled; count++ ) + if ( xc_get_gnttab_frames(xc_handle, + dom, + page_array + 1 + nr_pages, + NR_GRANT_FRAMES) <= 0) { + fprintf(stderr, "cannot get grant table frames\n"); + goto error_out; + } + + for ( count = 0; count < nr_pages + 1 + NR_GRANT_FRAMES; count++ ) { if ( xc_add_mmu_update( xc_handle, mmu, diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index 75556f6847..8993af0b57 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -314,6 +314,35 @@ int xc_get_pfn_list(int xc_handle, return (ret < 0) ? -1 : op.u.getmemlist.num_pfns; } +int xc_get_gnttab_frames(int xc_handle, + uint32_t domid, + unsigned long *pfn_buf, + unsigned long max_pfns) +{ + DECLARE_DOM0_OP; + int ret; + op.cmd = DOM0_GETGNTTABLIST; + op.u.getgnttablist.domain = (domid_t)domid; + op.u.getgnttablist.max_pfns = max_pfns; + op.u.getgnttablist.buffer = pfn_buf; + +#ifdef VALGRIND + memset(pfn_buf, 0, max_pfns * sizeof(unsigned long)); +#endif + + if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 ) + { + PERROR("xc_get_pfn_list: pfn_buf mlock failed"); + return -1; + } + + ret = do_dom0_op(xc_handle, &op); + + safe_munlock(pfn_buf, max_pfns * sizeof(unsigned long)); + + return (ret < 0) ? -1 : op.u.getgnttablist.num_pfns; +} + long xc_get_tot_pages(int xc_handle, uint32_t domid) { DECLARE_DOM0_OP; diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h index 8c19ecd218..b366db69e5 100644 --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -111,6 +111,9 @@ static inline int do_dom0_op(int xc_handle, dom0_op_t *op) return ret; } +int xc_get_gnttab_frames(int xc_handle, uint32_t domid, unsigned long *pfn_buf, + unsigned long max_pfns); + /* * ioctl-based mfn mapping interface diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 789d01899a..4a61ba4948 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -330,6 +330,38 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) } break; + case DOM0_GETGNTTABLIST: + { + int i; + struct domain *d = find_domain_by_id(op->u.getgnttablist.domain); + unsigned long max_pfns = op->u.getgnttablist.max_pfns; + unsigned long pfn; + unsigned long *buffer = op->u.getgnttablist.buffer; + + ret = -EINVAL; + if ( d != NULL ) + { + ret = 0; + + for ( i = 0; i < max_pfns && i < NR_GRANT_FRAMES; i++ ) + { + pfn = gnttab_shared_mfn(d, d->grant_table, i); + if ( put_user(pfn, buffer) ) + { + ret = -EFAULT; + break; + } + buffer++; + } + + op->u.getgnttablist.num_pfns = i; + copy_to_user(u_dom0_op, op, sizeof(*op)); + + put_domain(d); + } + } + break; + case DOM0_GETMEMLIST: { int i; diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 7576d715d3..3f788ca34f 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -481,6 +481,7 @@ gnttab_setup_table( gnttab_setup_table_t op; struct domain *d; int i; + unsigned long mfn; if ( count != 1 ) return -EINVAL; @@ -520,9 +521,12 @@ gnttab_setup_table( { ASSERT(d->grant_table != NULL); (void)put_user(GNTST_okay, &uop->status); - for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user(gnttab_shared_mfn(d, d->grant_table, i), - &op.frame_list[i]); + for ( i = 0; i < op.nr_frames; i++ ) { + mfn = gnttab_shared_mfn(d, d->grant_table, i); + if (shadow_mode_translate(d)) + mfn = __mfn_to_gpfn(d, mfn); + (void)put_user(mfn, &op.frame_list[i]); + } } put_domain(d); diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 4a70a77e49..6d6a04594e 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -430,7 +430,17 @@ typedef struct { domid_t domain; /* domain to be affected */ unsigned long mfn; /* machine frame to be initialised */ } dom0_hypercall_init_t; - + +#define DOM0_GETGNTTABLIST 49 +typedef struct { + /* IN variables. */ + domid_t domain; + unsigned long max_pfns; + void *buffer; + /* OUT variables. */ + unsigned long num_pfns; +} dom0_getgnttablist_t; + typedef struct { uint32_t cmd; uint32_t interface_version; /* DOM0_INTERFACE_VERSION */ @@ -472,6 +482,7 @@ typedef struct { dom0_irq_permission_t irq_permission; dom0_iomem_permission_t iomem_permission; dom0_hypercall_init_t hypercall_init; + dom0_getgnttablist_t getgnttablist; uint8_t pad[128]; } u; } dom0_op_t;