[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] mini-os: arm: grant mapping
Hi, I’ve been playing with grant mapping on arm mini-os. Specifically I’ve made vchan ‘clients' (which act as backends, mapping frontend aka ‘server’ pages) work with some extremely hacky patches and I’m curious to know what you think and especially, how it should really be done. Current arch/arm/mm.c has a missing populate_ondemand function: unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) { // FIXME BUG(); } I notice the arch/x86/mm.c version looks for runs of free frames in the page table. I notice that gntmap_munmap doesn’t have any corresponding call to free so I assume the act of unmapping the grant causes Xen to mark the pages as free for you — is this correct? Would a similar trick work on arm or would we have to manage the memory explicitly ourselves? I also noticed that the x86 version initialises the “demand mapping area” from “max_pfn” in mm.c. I’m a bit suspicious about this on arm since the grant table is being mapped in somewhere pre-ordained in the device tree (If I’m reading it correctly) and there could be an overlap (if we’re unlucky). Anyway, as an experiment I hade a trivial memory allocator for a small number of pages which tracks used/free (and which doesn’t even support freeing memory): diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c index 813a34e..86dd43c 100644 --- a/extras/mini-os/arch/arm/mm.c +++ b/extras/mini-os/arch/arm/mm.c @@ -9,12 +9,6 @@ void arm_map_extra_stack_section(int); uint32_t physical_address_offset; -unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) -{ - // FIXME - BUG(); -} - void arch_init_mm(unsigned long *start_pfn_p, unsigned long *max_pfn_p) { int memory; @@ -86,8 +80,59 @@ void arch_init_p2m(unsigned long max_pfn) { } +static unsigned long demand_map_area_start; +#define DEMAND_MAP_PAGES 160 /* 640 KiB is enough for anyone */ + +// FIXME: the x86 backend doesn't track free/in-use explicitly +// because it can read the pagetable. Can we do that too? + +// FIXME: because of the above there isn't a way to mark a page +// as free, so we leak. + +/* One whole byte to signal free (true) or in-use (false) */ +static char demand_map_area_free[DEMAND_MAP_PAGES]; + void arch_init_demand_mapping_area(unsigned long cur_pfn) { + int i; + cur_pfn++; + printk("Next pfn = 0x%lx (== %p VA)\n", cur_pfn, pfn_to_virt(cur_pfn)); + + demand_map_area_start = (unsigned long) pfn_to_virt(cur_pfn); + cur_pfn += DEMAND_MAP_PAGES; + printk("Demand map memory at 0x%lx-0x%p.\n", + demand_map_area_start, pfn_to_virt(cur_pfn)); + for (i = 0; i < DEMAND_MAP_PAGES; i++ ) { + demand_map_area_free[i] = 1; + } +} + +unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) +{ + int i, j, found; + unsigned long addr; + if (alignment != 1) { + printk("allocate_ondemand: we only support alignment = 1 (was: %ld)\n", alignment); + BUG(); + } + for (i = 0, j = 0; i < DEMAND_MAP_PAGES - n; i += j+1 ) { + /* Is the contiguous section free? */ + found = 0; + for (j = 0; j < n; j++ ) + if (!demand_map_area_free[i+j]) { + found = 1; + break; + } + if (found) continue; + /* It's free, so allocate it. */ + for (j = 0; j < n; j++ ) + demand_map_area_free[i+j] = 0; + addr = demand_map_area_start + i * PAGE_SIZE; + printk("allocate_ondemand(%ld, %ld) returning %lx\n", n, alignment, addr); + return addr; + } + printk("allocate_ondemand: demand map area is full.\n"); + BUG(); } /* Get Xen's suggested physical page assignments for the grant table. */ With this it still didn’t work: the grant map hypercall succeeded but the data just wasn’t there. I had a read of the hypercall doc which describes the address as * 2. If GNTMAP_host_map is specified then a mapping will be added at * either a host virtual address in the current address space, or at * a PTE at the specified machine address. I’m not totally sure what a ‘host virtual address’ refers to but I notice the address we’re using in the call is the regular virtual address (the one we can simply deref and read the data). As an experiment I wrapped it via the to_phys macro and suddenly it worked: diff --git a/extras/mini-os/gntmap.c b/extras/mini-os/gntmap.c index f6ab3ad..328d953 100644 --- a/extras/mini-os/gntmap.c +++ b/extras/mini-os/gntmap.c @@ -205,11 +205,12 @@ gntmap_map_grant_refs(struct gntmap *map, if (addr == 0) return NULL; + // FIXME: to_phys below is probably wrong on x86 for (i = 0; i < count; i++) { ent = gntmap_find_free_entry(map); if (ent == NULL || _gntmap_map_grant_ref(ent, - addr + PAGE_SIZE * i, + to_phys(addr + PAGE_SIZE * i), domids[i * domids_stride], refs[i], writable) != 0) { where in arch/arm/include/arch_mm.h: #define to_phys(x) (((paddr_t)(x)+physical_address_offset) & 0xffffffff) Of course this might be the wrong thing to do— it might break x86 where: #define VIRT_START ((unsigned long)&_text) #define to_phys(x) ((unsigned long)(x)-VIRT_START) I’ve not had a chance to see whether this breaks x86. Certainly x86 worked before my patch. Anyway I’d appreciate any feedback you may have :-) Apart from this (and a workaround-able problem involving timers) minios on arm is working nicely for me — thanks for that! Cheers, Dave _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |