mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
common: add a new mappable resource type: XENMEM_resource_grant_table
This patch allows grant table frames to be mapped using the
XENMEM_acquire_resource memory op.
NOTE: This patch expands the on-stack mfn_list array in acquire_resource()
but it is still small enough to remain on-stack.
NOTE: This patch also removes a bogus comment above the
grant_to_status_frames() function.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
[Rebase over "Explicitly default to gnttab v1 during domain creation"]
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
1 parent
1237659523
commit
83fa6552ce
4 files changed
+165
-15
No files matched your search
+100
-14
@@ -351,12 +351,17 @@ static inline void active_entry_release(struct active_grant_entry *act)
|
||||
|
||||
#define GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t))
|
||||
#define GRANT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t))
|
||||
/* Number of grant table status entries. Caller must hold d's gr. table lock.*/
|
||||
|
||||
static inline unsigned int grant_to_status_frames(unsigned int grant_frames)
|
||||
{
|
||||
return DIV_ROUND_UP(grant_frames * GRANT_PER_PAGE, GRANT_STATUS_PER_PAGE);
|
||||
}
|
||||
|
||||
static inline unsigned int status_to_grant_frames(unsigned int status_frames)
|
||||
{
|
||||
return DIV_ROUND_UP(status_frames * GRANT_STATUS_PER_PAGE, GRANT_PER_PAGE);
|
||||
}
|
||||
|
||||
/* Check if the page has been paged out, or needs unsharing.
|
||||
If rc == GNTST_okay, *page contains the page struct with a ref taken.
|
||||
Caller must do put_page(*page).
|
||||
@@ -3840,6 +3845,70 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* caller must hold write lock */
|
||||
static int gnttab_get_status_frame_mfn(struct domain *d,
|
||||
unsigned long idx, mfn_t *mfn)
|
||||
{
|
||||
const struct grant_table *gt = d->grant_table;
|
||||
|
||||
ASSERT(gt->gt_version == 2);
|
||||
|
||||
if ( idx >= nr_status_frames(gt) )
|
||||
{
|
||||
unsigned long nr_status;
|
||||
unsigned long nr_grant;
|
||||
|
||||
nr_status = idx + 1; /* sufficient frames to make idx valid */
|
||||
|
||||
if ( nr_status == 0 ) /* overflow? */
|
||||
return -EINVAL;
|
||||
|
||||
nr_grant = status_to_grant_frames(nr_status);
|
||||
|
||||
if ( grant_to_status_frames(nr_grant) != nr_status ) /* overflow? */
|
||||
return -EINVAL;
|
||||
|
||||
if ( nr_grant <= gt->max_grant_frames )
|
||||
gnttab_grow_table(d, nr_grant);
|
||||
|
||||
/* check whether gnttab_grow_table() succeeded */
|
||||
if ( idx >= nr_status_frames(gt) )
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*mfn = _mfn(virt_to_mfn(gt->status[idx]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* caller must hold write lock */
|
||||
static int gnttab_get_shared_frame_mfn(struct domain *d,
|
||||
unsigned long idx, mfn_t *mfn)
|
||||
{
|
||||
const struct grant_table *gt = d->grant_table;
|
||||
|
||||
ASSERT(gt->gt_version != 0);
|
||||
|
||||
if ( idx >= nr_grant_frames(gt) )
|
||||
{
|
||||
unsigned long nr_grant;
|
||||
|
||||
nr_grant = idx + 1; /* sufficient frames to make idx valid */
|
||||
|
||||
if ( nr_grant == 0 ) /* overflow? */
|
||||
return -EINVAL;
|
||||
|
||||
if ( nr_grant <= gt->max_grant_frames )
|
||||
gnttab_grow_table(d, nr_grant);
|
||||
|
||||
/* check whether gnttab_grow_table() succeeded */
|
||||
if ( idx >= nr_grant_frames(gt) )
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*mfn = _mfn(virt_to_mfn(gt->shared_raw[idx]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
mfn_t *mfn)
|
||||
{
|
||||
@@ -3854,21 +3923,11 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
{
|
||||
idx &= ~XENMAPIDX_grant_table_status;
|
||||
status = true;
|
||||
if ( idx < nr_status_frames(gt) )
|
||||
*mfn = _mfn(virt_to_mfn(gt->status[idx]));
|
||||
else
|
||||
rc = -EINVAL;
|
||||
|
||||
rc = gnttab_get_status_frame_mfn(d, idx, mfn);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (idx >= nr_grant_frames(gt)) && (idx < gt->max_grant_frames) )
|
||||
gnttab_grow_table(d, idx + 1);
|
||||
|
||||
if ( idx < nr_grant_frames(gt) )
|
||||
*mfn = _mfn(virt_to_mfn(gt->shared_raw[idx]));
|
||||
else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
rc = gnttab_get_shared_frame_mfn(d, idx, mfn);
|
||||
|
||||
if ( !rc && paging_mode_translate(d) &&
|
||||
!gfn_eq(gnttab_get_frame_gfn(gt, status, idx), INVALID_GFN) )
|
||||
@@ -3883,6 +3942,33 @@ int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gnttab_get_shared_frame(struct domain *d, unsigned long idx,
|
||||
mfn_t *mfn)
|
||||
{
|
||||
struct grant_table *gt = d->grant_table;
|
||||
int rc;
|
||||
|
||||
grant_write_lock(gt);
|
||||
rc = gnttab_get_shared_frame_mfn(d, idx, mfn);
|
||||
grant_write_unlock(gt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gnttab_get_status_frame(struct domain *d, unsigned long idx,
|
||||
mfn_t *mfn)
|
||||
{
|
||||
struct grant_table *gt = d->grant_table;
|
||||
int rc;
|
||||
|
||||
grant_write_lock(gt);
|
||||
rc = (gt->gt_version == 2) ?
|
||||
gnttab_get_status_frame_mfn(d, idx, mfn) : -EINVAL;
|
||||
grant_write_unlock(gt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void gnttab_usage_print(struct domain *rd)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
+55
-1
@@ -23,6 +23,7 @@
|
||||
#include <xen/numa.h>
|
||||
#include <xen/mem_access.h>
|
||||
#include <xen/trace.h>
|
||||
#include <xen/grant_table.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/p2m.h>
|
||||
@@ -982,6 +983,44 @@ static long xatp_permission_check(struct domain *d, unsigned int space)
|
||||
return xsm_add_to_physmap(XSM_TARGET, current->domain, d);
|
||||
}
|
||||
|
||||
static int acquire_grant_table(struct domain *d, unsigned int id,
|
||||
unsigned long frame,
|
||||
unsigned int nr_frames,
|
||||
xen_pfn_t mfn_list[])
|
||||
{
|
||||
unsigned int i = nr_frames;
|
||||
|
||||
/* Iterate backwards in case table needs to grow */
|
||||
while ( i-- != 0 )
|
||||
{
|
||||
mfn_t mfn = INVALID_MFN;
|
||||
int rc;
|
||||
|
||||
switch ( id )
|
||||
{
|
||||
case XENMEM_resource_grant_table_id_shared:
|
||||
rc = gnttab_get_shared_frame(d, frame + i, &mfn);
|
||||
break;
|
||||
|
||||
case XENMEM_resource_grant_table_id_status:
|
||||
rc = gnttab_get_status_frame(d, frame + i, &mfn);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
ASSERT(!mfn_eq(mfn, INVALID_MFN));
|
||||
mfn_list[i] = mfn_x(mfn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_resource(
|
||||
XEN_GUEST_HANDLE_PARAM(xen_mem_acquire_resource_t) arg)
|
||||
{
|
||||
@@ -992,7 +1031,7 @@ static int acquire_resource(
|
||||
* moment since they are small, but if they need to grow in future
|
||||
* use-cases then per-CPU arrays or heap allocations may be required.
|
||||
*/
|
||||
xen_pfn_t mfn_list[2];
|
||||
xen_pfn_t mfn_list[32];
|
||||
int rc;
|
||||
|
||||
if ( copy_from_guest(&xmar, arg, 1) )
|
||||
@@ -1027,6 +1066,11 @@ static int acquire_resource(
|
||||
|
||||
switch ( xmar.type )
|
||||
{
|
||||
case XENMEM_resource_grant_table:
|
||||
rc = acquire_grant_table(d, xmar.id, xmar.frame, xmar.nr_frames,
|
||||
mfn_list);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = arch_acquire_resource(d, xmar.type, xmar.id, xmar.frame,
|
||||
xmar.nr_frames, mfn_list, &xmar.flags);
|
||||
@@ -1046,6 +1090,16 @@ static int acquire_resource(
|
||||
xen_pfn_t gfn_list[ARRAY_SIZE(mfn_list)];
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* FIXME: Until foreign pages inserted into the P2M are properly
|
||||
* reference counted, it is unsafe to allow mapping of
|
||||
* non-caller-owned resource pages unless the caller is
|
||||
* the hardware domain.
|
||||
*/
|
||||
if ( !(xmar.flags & XENMEM_rsrc_acq_caller_owned) &&
|
||||
!is_hardware_domain(currd) )
|
||||
return -EACCES;
|
||||
|
||||
if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) )
|
||||
rc = -EFAULT;
|
||||
|
||||
|
||||
@@ -611,14 +611,20 @@ struct xen_mem_acquire_resource {
|
||||
uint16_t type;
|
||||
|
||||
#define XENMEM_resource_ioreq_server 0
|
||||
#define XENMEM_resource_grant_table 1
|
||||
|
||||
/*
|
||||
* IN - a type-specific resource identifier, which must be zero
|
||||
* unless stated otherwise.
|
||||
*
|
||||
* type == XENMEM_resource_ioreq_server -> id == ioreq server id
|
||||
* type == XENMEM_resource_grant_table -> id defined below
|
||||
*/
|
||||
uint32_t id;
|
||||
|
||||
#define XENMEM_resource_grant_table_id_shared 0
|
||||
#define XENMEM_resource_grant_table_id_status 1
|
||||
|
||||
/*
|
||||
* IN/OUT - As an IN parameter number of frames of the resource
|
||||
* to be mapped. However, if the specified value is 0 and
|
||||
|
||||
@@ -58,6 +58,10 @@ int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
|
||||
|
||||
int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
mfn_t *mfn);
|
||||
int gnttab_get_shared_frame(struct domain *d, unsigned long idx,
|
||||
mfn_t *mfn);
|
||||
int gnttab_get_status_frame(struct domain *d, unsigned long idx,
|
||||
mfn_t *mfn);
|
||||
|
||||
unsigned int gnttab_dom0_frames(void);
|
||||
|
||||
|
||||