[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] mini-os: arm: grant mapping


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

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, 
+        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 ||
-                                  addr + PAGE_SIZE * i,
+                                  to_phys(addr + PAGE_SIZE * i),
                                   domids[i * domids_stride],
                                   writable) != 0) {

where in arch/arm/include/arch_mm.h:

#define to_phys(x)                 (((paddr_t)(x)+physical_address_offset) & 

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!


Xen-devel mailing list



Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.