Skip to content

Commit 14ac666

Browse files
soburikartben
authored andcommitted
drivers: xen: change gnttab_[get|put]_pages for multi-page support
Replace `gnttab_get_page()`/`gnttab_put_pabes(addr)` with `gnttab_get_pages(npages)`/`gnttab_put_pages(addr, npages)` for supporting multi-page operation. Note: This is a breaking change, update callers accordingly. Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 40e5f73 commit 14ac666

File tree

2 files changed

+72
-36
lines changed

2 files changed

+72
-36
lines changed

drivers/xen/gnttab.c

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <zephyr/arch/arm64/hypercall.h>
2121
#include <zephyr/xen/generic.h>
2222
#include <zephyr/xen/gnttab.h>
23+
#include <zephyr/xen/memory.h>
2324
#include <zephyr/xen/public/grant_table.h>
2425
#include <zephyr/xen/public/memory.h>
2526
#include <zephyr/xen/public/xen.h>
@@ -193,61 +194,93 @@ static void gop_eagain_retry(int cmd, struct gnttab_map_grant_ref *gref)
193194
}
194195
}
195196

196-
void *gnttab_get_page(void)
197+
void *gnttab_get_pages(unsigned int npages)
197198
{
198199
int ret;
199200
void *page_addr;
200-
struct xen_remove_from_physmap rfpm;
201+
unsigned int removed;
202+
xen_pfn_t gfn;
201203

202-
page_addr = k_aligned_alloc(XEN_PAGE_SIZE, XEN_PAGE_SIZE);
203-
if (!page_addr) {
204-
LOG_WRN("Failed to allocate memory for gnttab page!\n");
204+
if (npages == 0) {
205205
return NULL;
206206
}
207207

208-
rfpm.domid = DOMID_SELF;
209-
rfpm.gpfn = xen_virt_to_gfn(page_addr);
208+
page_addr = k_aligned_alloc(XEN_PAGE_SIZE, XEN_PAGE_SIZE * npages);
209+
if (!page_addr) {
210+
LOG_WRN("Failed to allocate memory for gnttab %u pages!", npages);
211+
return NULL;
212+
}
210213

211214
/*
212215
* GNTTABOP_map_grant_ref will simply replace the entry in the P2M
213216
* and not release any RAM that may have been associated with
214217
* page_addr, so we release this memory before mapping.
215218
*/
216-
ret = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &rfpm);
219+
for (removed = 0; removed < npages; removed++) {
220+
gfn = xen_virt_to_gfn(page_addr) + removed;
221+
222+
ret = xendom_remove_from_physmap(DOMID_SELF, gfn);
223+
if (ret) {
224+
break;
225+
}
226+
}
227+
217228
if (ret) {
218-
LOG_WRN("Failed to remove gnttab page from physmap, ret = %d\n", ret);
229+
LOG_WRN("xendom_remove_from_physmap failed: ret=%d, removed=%u, gfn=%llx",
230+
ret, removed, (uint64_t)gfn);
231+
232+
if (removed > 0) {
233+
ret = gnttab_put_pages(page_addr, removed);
234+
if (ret) {
235+
LOG_ERR("gnttab_put_pages failed ret=%d addr=%p", ret, page_addr);
236+
k_panic();
237+
}
238+
}
239+
219240
return NULL;
220241
}
221242

222243
return page_addr;
223244
}
224245

225-
void gnttab_put_page(void *page_addr)
246+
int gnttab_put_pages(void *start_addr, unsigned int npages)
226247
{
227-
int ret, nr_extents = 1;
248+
int ret;
249+
size_t i;
228250
struct xen_memory_reservation reservation;
229-
xen_pfn_t page = xen_virt_to_gfn(page_addr);
251+
xen_pfn_t *pages;
252+
253+
if (npages == 0) {
254+
return -EINVAL;
255+
}
256+
257+
pages = k_malloc(sizeof(*pages) * npages);
258+
if (pages == NULL) {
259+
LOG_WRN("Failed to allocate memory: npages=%u", npages);
260+
return -ENOMEM;
261+
}
262+
263+
for (i = 0; i < npages; i++) {
264+
pages[i] = xen_virt_to_gfn(start_addr) + i;
265+
}
230266

231-
/*
232-
* After unmapping there will be a 4Kb holes in address space
233-
* at 'page_addr' positions. To keep it contiguous and be able
234-
* to return such addresses to memory allocator we need to
235-
* populate memory on unmapped positions here.
236-
*/
237267
memset(&reservation, 0, sizeof(reservation));
238268
reservation.domid = DOMID_SELF;
239269
reservation.extent_order = 0;
240-
reservation.nr_extents = nr_extents;
241-
set_xen_guest_handle(reservation.extent_start, &page);
270+
reservation.nr_extents = npages;
271+
set_xen_guest_handle(reservation.extent_start, pages);
242272

243273
ret = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
244-
if (ret != nr_extents) {
245-
LOG_WRN("failed to populate physmap on gfn = 0x%llx, ret = %d\n",
246-
page, ret);
247-
return;
274+
if (ret != npages) {
275+
LOG_WRN("failed to populate physmap, ret = %d (npages=%u)", ret, npages);
276+
k_free(pages);
277+
return -EIO;
248278
}
249279

250-
k_free(page_addr);
280+
k_free(pages);
281+
k_free(start_addr);
282+
283+
return 0;
251284
}
252285

253286
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned int count)

include/zephyr/xen/gnttab.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,25 @@ int gnttab_end_access(grant_ref_t gref);
4141
int32_t gnttab_alloc_and_grant(void **map, bool readonly);
4242

4343
/*
44-
* Provides interface to acquire free page, that can be used for
45-
* mapping of foreign frames. Should be freed by gnttab_put_page()
46-
* after usage.
44+
* Provides interface to acquire one or more pages that can be used for
45+
* mapping of foreign frames. Should be freed by gnttab_put_pages()
46+
* after use.
4747
*
48+
* @param npages - number of pages to allocate.
4849
* @return - pointer to page start address, that can be used as host_addr
4950
* in struct gnttab_map_grant_ref, NULL on error.
5051
*/
51-
void *gnttab_get_page(void);
52+
void *gnttab_get_pages(unsigned int npages);
5253

5354
/*
54-
* Releases provided page, that was used for mapping foreign grant frame,
55+
* Releases pages that were used for mapping foreign grant frames,
5556
* should be called after unmapping.
5657
*
57-
* @param page_addr - pointer to start address of used page.
58+
* @param start_addr - pointer to start address of allocated buffer.
59+
* @param npages - number of pages allocated for the buffer.
60+
* @return - zero on success, non-zero on failure
5861
*/
59-
void gnttab_put_page(void *page_addr);
62+
int gnttab_put_pages(void *start_addr, unsigned int npages);
6063

6164
/*
6265
* Maps foreign grant ref to Zephyr address space.
@@ -66,15 +69,15 @@ void gnttab_put_page(void *page_addr);
6669
* @return - zero on success or negative errno on failure
6770
* also per-page status will be set in map_ops[i].status (GNTST_*)
6871
*
69-
* To map foreign frame you need 4K-aligned 4K memory page, which will be
70-
* used as host_addr for grant mapping - it should be acquired by gnttab_get_page()
72+
* To map foreign frames you need 4K-aligned memory pages, which will be
73+
* used as host_addr for grant mapping - it should be acquired by gnttab_get_pages()
7174
* function.
7275
*/
7376
int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned int count);
7477

7578
/*
76-
* Unmap foreign grant refs. The gnttab_put_page() should be used after this for
77-
* each page, that was successfully unmapped.
79+
* Unmap foreign grant refs. The gnttab_put_pages() should be used after this for
80+
* pages that were successfully unmapped.
7881
*
7982
* @param unmap_ops - array of prepared gnttab_unmap_grant_ref's for unmapping
8083
* @param count - number of grefs in unmap_ops array

0 commit comments

Comments
 (0)