1 /******************************************************************************
2  *
3  * Copyright (c) 2007-2008, D G Murray <Derek.Murray@cl.cam.ac.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "xc_private.h"
20 
xc_gnttab_op(xc_interface * xch,int cmd,void * op,int op_size,int count)21 int xc_gnttab_op(xc_interface *xch, int cmd, void * op, int op_size, int count)
22 {
23     int ret = 0;
24     DECLARE_HYPERCALL_BOUNCE(op, count * op_size, XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
25 
26     if ( xc_hypercall_bounce_pre(xch, op) )
27     {
28         PERROR("Could not bounce buffer for grant table op hypercall");
29         goto out1;
30     }
31 
32     ret = xencall3(xch->xcall,  __HYPERVISOR_grant_table_op,
33                    cmd, HYPERCALL_BUFFER_AS_ARG(op), count);
34 
35     xc_hypercall_bounce_post(xch, op);
36 
37  out1:
38     return ret;
39 }
40 
xc_gnttab_query_size(xc_interface * xch,struct gnttab_query_size * query)41 int xc_gnttab_query_size(xc_interface *xch, struct gnttab_query_size *query)
42 {
43     int rc;
44 
45     rc = xc_gnttab_op(xch, GNTTABOP_query_size, query, sizeof(*query), 1);
46 
47     if ( rc || (query->status != GNTST_okay) )
48         ERROR("Could not query dom %u's grant size\n", query->dom);
49 
50     return rc;
51 }
52 
xc_gnttab_get_version(xc_interface * xch,uint32_t domid)53 int xc_gnttab_get_version(xc_interface *xch, uint32_t domid)
54 {
55     struct gnttab_get_version query;
56     int rc;
57 
58     query.dom = domid;
59     rc = xc_gnttab_op(xch, GNTTABOP_get_version, &query, sizeof(query),
60                       1);
61     if ( rc < 0 )
62         return rc;
63     else
64         return query.version;
65 }
66 
_gnttab_map_table(xc_interface * xch,uint32_t domid,int * gnt_num)67 static void *_gnttab_map_table(xc_interface *xch, uint32_t domid, int *gnt_num)
68 {
69     int rc, i;
70     struct gnttab_query_size query;
71     struct gnttab_setup_table setup;
72     DECLARE_HYPERCALL_BUFFER(unsigned long, frame_list);
73     xen_pfn_t *pfn_list = NULL;
74     grant_entry_v1_t *gnt = NULL;
75 
76     if ( !gnt_num )
77         return NULL;
78 
79     query.dom = domid;
80     rc = xc_gnttab_op(xch, GNTTABOP_query_size, &query, sizeof(query), 1);
81 
82     if ( rc || (query.status != GNTST_okay) )
83     {
84         ERROR("Could not query dom%d's grant size\n", domid);
85         return NULL;
86     }
87 
88     *gnt_num = query.nr_frames * (PAGE_SIZE / sizeof(grant_entry_v1_t) );
89 
90     frame_list = xc_hypercall_buffer_alloc(xch, frame_list, query.nr_frames * sizeof(unsigned long));
91     if ( !frame_list )
92     {
93         ERROR("Could not allocate frame_list in xc_gnttab_map_table\n");
94         return NULL;
95     }
96 
97     pfn_list = malloc(query.nr_frames * sizeof(xen_pfn_t));
98     if ( !pfn_list )
99     {
100         ERROR("Could not allocate pfn_list in xc_gnttab_map_table\n");
101         goto err;
102     }
103 
104     setup.dom = domid;
105     setup.nr_frames = query.nr_frames;
106     set_xen_guest_handle(setup.frame_list, frame_list);
107 
108     /* XXX Any race with other setup_table hypercall? */
109     rc = xc_gnttab_op(xch, GNTTABOP_setup_table, &setup, sizeof(setup),
110                       1);
111 
112     if ( rc || (setup.status != GNTST_okay) )
113     {
114         ERROR("Could not get grant table frame list\n");
115         goto err;
116     }
117 
118     for ( i = 0; i < setup.nr_frames; i++ )
119         pfn_list[i] = frame_list[i];
120 
121     gnt = xc_map_foreign_pages(xch, domid, PROT_READ, pfn_list,
122                                setup.nr_frames);
123     if ( !gnt )
124     {
125         ERROR("Could not map grant table\n");
126         goto err;
127     }
128 
129 err:
130     if ( frame_list )
131         xc_hypercall_buffer_free(xch, frame_list);
132     free(pfn_list);
133 
134     return gnt;
135 }
136 
xc_gnttab_map_table_v1(xc_interface * xch,uint32_t domid,int * gnt_num)137 grant_entry_v1_t *xc_gnttab_map_table_v1(xc_interface *xch, uint32_t domid,
138                                          int *gnt_num)
139 {
140     if (xc_gnttab_get_version(xch, domid) == 2)
141         return NULL;
142     return _gnttab_map_table(xch, domid, gnt_num);
143 }
144 
xc_gnttab_map_table_v2(xc_interface * xch,uint32_t domid,int * gnt_num)145 grant_entry_v2_t *xc_gnttab_map_table_v2(xc_interface *xch, uint32_t domid,
146                                          int *gnt_num)
147 {
148     if (xc_gnttab_get_version(xch, domid) != 2)
149         return NULL;
150     return _gnttab_map_table(xch, domid, gnt_num);
151 }
152 
153 /*
154  * Local variables:
155  * mode: C
156  * c-file-style: "BSD"
157  * c-basic-offset: 4
158  * tab-width: 4
159  * indent-tabs-mode: nil
160  * End:
161  */
162