|
20 | 20 | #include <zephyr/arch/arm64/hypercall.h>
|
21 | 21 | #include <zephyr/xen/generic.h>
|
22 | 22 | #include <zephyr/xen/gnttab.h>
|
| 23 | +#include <zephyr/xen/memory.h> |
23 | 24 | #include <zephyr/xen/public/grant_table.h>
|
24 | 25 | #include <zephyr/xen/public/memory.h>
|
25 | 26 | #include <zephyr/xen/public/xen.h>
|
@@ -193,61 +194,93 @@ static void gop_eagain_retry(int cmd, struct gnttab_map_grant_ref *gref)
|
193 | 194 | }
|
194 | 195 | }
|
195 | 196 |
|
196 |
| -void *gnttab_get_page(void) |
| 197 | +void *gnttab_get_pages(unsigned int npages) |
197 | 198 | {
|
198 | 199 | int ret;
|
199 | 200 | void *page_addr;
|
200 |
| - struct xen_remove_from_physmap rfpm; |
| 201 | + unsigned int removed; |
| 202 | + xen_pfn_t gfn; |
201 | 203 |
|
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) { |
205 | 205 | return NULL;
|
206 | 206 | }
|
207 | 207 |
|
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 | + } |
210 | 213 |
|
211 | 214 | /*
|
212 | 215 | * GNTTABOP_map_grant_ref will simply replace the entry in the P2M
|
213 | 216 | * and not release any RAM that may have been associated with
|
214 | 217 | * page_addr, so we release this memory before mapping.
|
215 | 218 | */
|
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 | + |
217 | 228 | 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 | + |
219 | 240 | return NULL;
|
220 | 241 | }
|
221 | 242 |
|
222 | 243 | return page_addr;
|
223 | 244 | }
|
224 | 245 |
|
225 |
| -void gnttab_put_page(void *page_addr) |
| 246 | +int gnttab_put_pages(void *start_addr, unsigned int npages) |
226 | 247 | {
|
227 |
| - int ret, nr_extents = 1; |
| 248 | + int ret; |
| 249 | + size_t i; |
228 | 250 | 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 | + } |
230 | 266 |
|
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 |
| - */ |
237 | 267 | memset(&reservation, 0, sizeof(reservation));
|
238 | 268 | reservation.domid = DOMID_SELF;
|
239 | 269 | 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); |
242 | 272 |
|
243 | 273 | 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; |
248 | 278 | }
|
249 | 279 |
|
250 |
| - k_free(page_addr); |
| 280 | + k_free(pages); |
| 281 | + k_free(start_addr); |
| 282 | + |
| 283 | + return 0; |
251 | 284 | }
|
252 | 285 |
|
253 | 286 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, unsigned int count)
|
|
0 commit comments