@@ -3987,6 +3987,29 @@ static int gnttab_get_shared_frame_mfn(struct domain *d,
return 0;
}
+unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id)
+{
+ const struct grant_table *gt = d->grant_table;
+ unsigned int nr = 0;
+
+ /* Don't need the grant lock. This limit is fixed at domain create time. */
+ switch ( id )
+ {
+ case XENMEM_resource_grant_table_id_shared:
+ nr = gt->max_grant_frames;
+ break;
+
+ case XENMEM_resource_grant_table_id_status:
+ if ( GNTTAB_MAX_VERSION < 2 )
+ break;
+
+ nr = grant_to_status_frames(gt->max_grant_frames);
+ break;
+ }
+
+ return nr;
+}
+
int gnttab_acquire_resource(
struct domain *d, unsigned int id, unsigned int frame,
unsigned int nr_frames, xen_pfn_t mfn_list[])
@@ -1054,6 +1054,42 @@ static long xatp_permission_check(struct domain *d, unsigned int space)
return xsm_add_to_physmap(XSM_TARGET, current->domain, d);
}
+unsigned int ioreq_server_max_frames(const struct domain *d)
+{
+ unsigned int nr = 0;
+
+#ifdef CONFIG_IOREQ_SERVER
+ if ( is_hvm_domain(d) )
+ /* One frame for the buf-ioreq ring, and one frame per 128 vcpus. */
+ nr = 1 + DIV_ROUND_UP(d->max_vcpus * sizeof(struct ioreq), PAGE_SIZE);
+#endif
+
+ return nr;
+}
+
+/*
+ * Return 0 on any kind of error. Caller converts to -EINVAL.
+ *
+ * All nonzero values should be repeatable (i.e. derived from some fixed
+ * property of the domain), and describe the full resource (i.e. mapping the
+ * result of this call will be the entire resource).
+ */
+static unsigned int resource_max_frames(const struct domain *d,
+ unsigned int type, unsigned int id)
+{
+ switch ( type )
+ {
+ case XENMEM_resource_grant_table:
+ return gnttab_resource_max_frames(d, id);
+
+ case XENMEM_resource_ioreq_server:
+ return ioreq_server_max_frames(d);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int acquire_ioreq_server(struct domain *d,
unsigned int id,
unsigned int frame,
@@ -1099,6 +1135,7 @@ static int acquire_resource(
* use-cases then per-CPU arrays or heap allocations may be required.
*/
xen_pfn_t mfn_list[32];
+ unsigned int max_frames;
int rc;
if ( !arch_acquire_resource_check(currd) )
@@ -1110,19 +1147,6 @@ static int acquire_resource(
if ( xmar.pad != 0 )
return -EINVAL;
- if ( guest_handle_is_null(xmar.frame_list) )
- {
- if ( xmar.nr_frames )
- return -EINVAL;
-
- xmar.nr_frames = ARRAY_SIZE(mfn_list);
-
- if ( __copy_field_to_guest(arg, &xmar, nr_frames) )
- return -EFAULT;
-
- return 0;
- }
-
if ( xmar.nr_frames > ARRAY_SIZE(mfn_list) )
return -E2BIG;
@@ -1147,6 +1171,22 @@ static int acquire_resource(
if ( rc )
goto out;
+ max_frames = resource_max_frames(d, xmar.type, xmar.id);
+
+ rc = -EINVAL;
+ if ( !max_frames )
+ goto out;
+
+ if ( guest_handle_is_null(xmar.frame_list) )
+ {
+ if ( xmar.nr_frames )
+ goto out;
+
+ xmar.nr_frames = max_frames;
+ rc = __copy_field_to_guest(arg, &xmar, nr_frames) ? -EFAULT : 0;
+ goto out;
+ }
+
switch ( xmar.type )
{
case XENMEM_resource_grant_table:
@@ -639,10 +639,19 @@ struct xen_mem_acquire_resource {
#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
- * frame_list is NULL then this field will be set to the
- * maximum value supported by the implementation on return.
+ * IN/OUT
+ *
+ * As an IN parameter number of frames of the resource to be mapped.
+ * This value may be updated over the course of the operation.
+ *
+ * When frame_list is NULL and nr_frames is 0, this is interpreted as a
+ * request for the size of the resource, which shall be returned in the
+ * nr_frames field.
+ *
+ * The size of a resource will never be zero, but a nonzero result doesn't
+ * guarantee that a subsequent mapping request will be successful. There
+ * are further type/id specific constraints which may change between the
+ * two calls.
*/
uint32_t nr_frames;
uint32_t pad;
@@ -56,6 +56,8 @@ 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);
+unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id);
+
int gnttab_acquire_resource(
struct domain *d, unsigned int id, unsigned int frame,
unsigned int nr_frames, xen_pfn_t mfn_list[]);
@@ -92,6 +94,12 @@ static inline int gnttab_map_frame(struct domain *d, unsigned long idx,
return -EINVAL;
}
+static inline unsigned int gnttab_resource_max_frames(
+ const struct domain *d, unsigned int id)
+{
+ return 0;
+}
+
static inline int gnttab_acquire_resource(
struct domain *d, unsigned int id, unsigned int frame,
unsigned int nr_frames, xen_pfn_t mfn_list[])