>From de12c5610baf4d6bcc4141038aa6058dde4732f0 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Wed, 8 Jul 2020 21:26:12 +1000 Subject: [PATCH 2/2] mach: vm_allocate_contiguous RPC now allows physical alignment/limits --- include/mach/mach.defs | 30 +++++++---------------- vm/vm_user.c | 55 +++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/include/mach/mach.defs b/include/mach/mach.defs index 77cc7d49..ed15a850 100644 --- a/include/mach/mach.defs +++ b/include/mach/mach.defs @@ -723,34 +723,22 @@ skip; /* old host_fpa_counters_reset */ * This routine is created for allocating DMA buffers. * We are going to get a contiguous physical memory * and its physical address in addition to the virtual address. + * We can specify physical memory range limits and alignment. */ - - /* XXX - This RPC lacks a few additional constraints like boundaries, alignment -and maybe phase. We may not use them now, but they're important for -portability (e.g. if GNU Mach supports PAE, drivers that can't use -physical memory beyond the 4 GiB limit must be able to express it). - -> What do you mean by "phase"? - -Offset from the alignment. But I don't think it's useful at all in this -case. Minimum and maximum addresses and alignment should do. Maybe -boundary crossing but usually, specifying the right alignment and size -is enough. - -For upstream -inclusion, we need to do it properly: the RPC should return a special -memory object (similar to device_map() ), which can then be mapped into -the process address space with vm_map() like any other memory object. - -phys_address_t? +/* XXX + * Future work: the RPC should return a special + * memory object (similar to device_map() ), which can then be mapped into + * the process address space with vm_map() like any other memory object. */ routine vm_allocate_contiguous( host_priv : host_priv_t; target_task : vm_task_t; out vaddr : vm_address_t; out paddr : vm_address_t; - size : vm_size_t); + size : vm_size_t; + pmin : vm_address_t; + pmax : vm_address_t; + palign : vm_size_t); /* * There is no more room in this interface for additional calls. diff --git a/vm/vm_user.c b/vm/vm_user.c index 1789dbfa..f74a1d54 100644 --- a/vm/vm_user.c +++ b/vm/vm_user.c @@ -532,21 +532,27 @@ kern_return_t vm_msync( return vm_map_msync(map, (vm_offset_t) address, size, sync_flags); } -kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, size) - host_t host_priv; - vm_map_t map; - vm_address_t *result_vaddr; - vm_address_t *result_paddr; - vm_size_t size; +kern_return_t vm_allocate_contiguous( + host_t host_priv, + vm_map_t map, + vm_address_t *result_vaddr, + vm_address_t *result_paddr, + vm_size_t size, + vm_address_t pmin, + vm_address_t pmax, + vm_size_t palign) { vm_size_t alloc_size; unsigned int npages; unsigned int i; unsigned int order; + unsigned int selector; vm_page_t pages; vm_object_t object; kern_return_t kr; vm_address_t vaddr; + vm_size_t phase; + vm_size_t nearest; if (host_priv == HOST_NULL) return KERN_INVALID_HOST; @@ -554,7 +560,28 @@ kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, if (map == VM_MAP_NULL) return KERN_INVALID_TASK; - size = vm_page_round(size); + /* FIXME */ + if (pmin != 0) + return KERN_INVALID_ARGUMENT; + + if (palign == 0) + palign = PAGE_SIZE; + + selector = VM_PAGE_SEL_DMA; +#if(VM_PAGE_MAX_SEGS == 4) + if (pmax > VM_PAGE_DMA_LIMIT) + selector = VM_PAGE_SEL_DMA32; + if (pmax > VM_PAGE_DMA32_LIMIT) + selector = VM_PAGE_SEL_DIRECTMAP; + if (pmax > VM_PAGE_DIRECTMAP_LIMIT) + selector = VM_PAGE_SEL_HIGHMEM; +#else + if (pmax > VM_PAGE_DMA_LIMIT) + selector = VM_PAGE_SEL_DIRECTMAP; + if (pmax > VM_PAGE_DIRECTMAP_LIMIT) + selector = VM_PAGE_SEL_HIGHMEM; +#endif + size = vm_page_round(size + palign); if (size == 0) return KERN_INVALID_ARGUMENT; @@ -573,7 +600,7 @@ kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, alloc_size = (1 << (order + PAGE_SHIFT)); npages = vm_page_atop(alloc_size); - pages = vm_page_grab_contig(alloc_size, VM_PAGE_SEL_DIRECTMAP); + pages = vm_page_grab_contig(alloc_size, selector); if (pages == NULL) { vm_object_deallocate(object); @@ -611,17 +638,21 @@ kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, return kr; } - kr = vm_map_pageable(map, vaddr, vaddr + size, + phase = vaddr % palign; + nearest = P2ALIGN(vaddr, palign); + size += phase; + + kr = vm_map_pageable(map, nearest, nearest + vm_page_round(size), VM_PROT_READ | VM_PROT_WRITE, TRUE, TRUE); if (kr != KERN_SUCCESS) { - vm_map_remove(map, vaddr, vaddr + size); + vm_map_remove(map, nearest, nearest + vm_page_round(size)); return kr; } - *result_vaddr = vaddr; - *result_paddr = pages->phys_addr; + *result_vaddr = vaddr + phase; + *result_paddr = pages->phys_addr + phase; return KERN_SUCCESS; } -- 2.25.1