ia64/xen-unstable

changeset 19355:2377bb2d0316

minios: allow to allocate machine contiguous pages

This is a port of XenLinux xen_alloc_contig_memory() to mini-os. A
sufficiently privileged mini-os guest can exchange a small number of
its pages with machine contiguous pages.

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@netronome.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Mar 13 07:37:24 2009 +0000 (2009-03-13)
parents c30742011bb8
children 3c1a88dc6fbe
files extras/mini-os/arch/ia64/mm.c extras/mini-os/arch/x86/mm.c extras/mini-os/include/mm.h extras/mini-os/include/x86/arch_mm.h
line diff
     1.1 --- a/extras/mini-os/arch/ia64/mm.c	Thu Mar 12 18:48:09 2009 +0000
     1.2 +++ b/extras/mini-os/arch/ia64/mm.c	Fri Mar 13 07:37:24 2009 +0000
     1.3 @@ -162,6 +162,12 @@ int unmap_frames(unsigned long virt_addr
     1.4      ASSERT(0);
     1.5  }
     1.6  
     1.7 +unsigned long alloc_contig_pages(int order, unsigned int addr_bits)
     1.8 +{
     1.9 +    /* TODO */
    1.10 +    ASSERT(0);
    1.11 +}
    1.12 +
    1.13  void arch_init_p2m(unsigned long max_pfn)
    1.14  {
    1.15      printk("Warn: p2m map not implemented.\n");
     2.1 --- a/extras/mini-os/arch/x86/mm.c	Thu Mar 12 18:48:09 2009 +0000
     2.2 +++ b/extras/mini-os/arch/x86/mm.c	Fri Mar 13 07:37:24 2009 +0000
     2.3 @@ -702,6 +702,148 @@ int unmap_frames(unsigned long va, unsig
     2.4  }
     2.5  
     2.6  /*
     2.7 + * Allocate pages which are contiguous in machine memory.
     2.8 + * Returns a VA to where they are mapped or 0 on failure.
     2.9 + * 
    2.10 + * addr_bits indicates if the region has restrictions on where it is
    2.11 + * located. Typical values are 32 (if for example PCI devices can't access
    2.12 + * 64bit memory) or 0 for no restrictions.
    2.13 + *
    2.14 + * Allocated pages can be freed using the page allocators free_pages() 
    2.15 + * function.
    2.16 + *
    2.17 + * based on Linux function xen_create_contiguous_region()
    2.18 + */
    2.19 +#define MAX_CONTIG_ORDER 9 /* 2MB */
    2.20 +unsigned long alloc_contig_pages(int order, unsigned int addr_bits)
    2.21 +{
    2.22 +    unsigned long in_va, va;
    2.23 +    unsigned long in_frames[1UL << order], out_frames, mfn;
    2.24 +    multicall_entry_t call[1UL << order];
    2.25 +    unsigned int i, num_pages = 1UL << order;
    2.26 +    int ret, exch_success;
    2.27 +
    2.28 +    /* pass in num_pages 'extends' of size 1 and
    2.29 +     * request 1 extend of size 'order */
    2.30 +    struct xen_memory_exchange exchange = {
    2.31 +        .in = {
    2.32 +            .nr_extents   = num_pages,
    2.33 +            .extent_order = 0,
    2.34 +            .domid        = DOMID_SELF
    2.35 +        },
    2.36 +        .out = {
    2.37 +            .nr_extents   = 1,
    2.38 +            .extent_order = order,
    2.39 +            .address_bits = addr_bits,
    2.40 +            .domid        = DOMID_SELF
    2.41 +        },
    2.42 +        .nr_exchanged = 0
    2.43 +    };
    2.44 +
    2.45 +    if ( order > MAX_CONTIG_ORDER )
    2.46 +    {
    2.47 +        printk("alloc_contig_pages: order too large 0x%x > 0x%x\n",
    2.48 +               order, MAX_CONTIG_ORDER);
    2.49 +        return 0;
    2.50 +    }
    2.51 +
    2.52 +    /* Allocate some potentially discontiguous pages */
    2.53 +    in_va = alloc_pages(order);
    2.54 +    if ( !in_va )
    2.55 +    {
    2.56 +        printk("alloc_contig_pages: could not get enough pages (order=0x%x\n",
    2.57 +               order);
    2.58 +        return 0;
    2.59 +    }
    2.60 +
    2.61 +    /* set up arguments for exchange hyper call */
    2.62 +    set_xen_guest_handle(exchange.in.extent_start, in_frames);
    2.63 +    set_xen_guest_handle(exchange.out.extent_start, &out_frames);
    2.64 +
    2.65 +    /* unmap current frames, keep a list of MFNs */
    2.66 +    for ( i = 0; i < num_pages; i++ )
    2.67 +    {
    2.68 +        int arg = 0;
    2.69 +
    2.70 +        va = in_va + (PAGE_SIZE * i);
    2.71 +        in_frames[i] = virt_to_mfn(va);
    2.72 +
    2.73 +        /* update P2M mapping */
    2.74 +        phys_to_machine_mapping[virt_to_pfn(va)] = INVALID_P2M_ENTRY;
    2.75 +
    2.76 +        /* build multi call */
    2.77 +        call[i].op = __HYPERVISOR_update_va_mapping;
    2.78 +        call[i].args[arg++] = va;
    2.79 +        call[i].args[arg++] = 0;
    2.80 +#ifdef __i386__
    2.81 +        call[i].args[arg++] = 0;
    2.82 +#endif  
    2.83 +        call[i].args[arg++] = UVMF_INVLPG;
    2.84 +    }
    2.85 +
    2.86 +    ret = HYPERVISOR_multicall(call, i);
    2.87 +    if ( ret )
    2.88 +    {
    2.89 +        printk("Odd, update_va_mapping hypercall failed with rc=%d.\n", ret);
    2.90 +        return 0;
    2.91 +    }
    2.92 +
    2.93 +    /* try getting a contig range of MFNs */
    2.94 +    out_frames = virt_to_pfn(in_va); /* PFNs to populate */
    2.95 +    ret = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
    2.96 +    if ( ret ) {
    2.97 +        printk("mem exchanged order=0x%x failed with rc=%d, nr_exchanged=%d\n", 
    2.98 +               order, ret, exchange.nr_exchanged);
    2.99 +        /* we still need to return the allocated pages above to the pool
   2.100 +         * ie. map them back into the 1:1 mapping etc. so we continue but 
   2.101 +         * in the end return the pages to the page allocator and return 0. */
   2.102 +        exch_success = 0;
   2.103 +    }
   2.104 +    else
   2.105 +        exch_success = 1;
   2.106 +
   2.107 +    /* map frames into 1:1 and update p2m */
   2.108 +    for ( i = 0; i < num_pages; i++ )
   2.109 +    {
   2.110 +        int arg = 0;
   2.111 +        pte_t pte;
   2.112 +
   2.113 +        va = in_va + (PAGE_SIZE * i);
   2.114 +        mfn = i < exchange.nr_exchanged ? (out_frames + i) : in_frames[i];
   2.115 +        pte = __pte(mfn << PAGE_SHIFT | L1_PROT);
   2.116 +
   2.117 +        /* update P2M mapping */
   2.118 +        phys_to_machine_mapping[virt_to_pfn(va)] = mfn;
   2.119 +
   2.120 +        /* build multi call */
   2.121 +        call[i].op = __HYPERVISOR_update_va_mapping;
   2.122 +        call[i].args[arg++] = va;
   2.123 +#ifdef __x86_64__
   2.124 +        call[i].args[arg++] = (pgentry_t)pte.pte;
   2.125 +#else
   2.126 +        call[i].args[arg++] = pte.pte_low;
   2.127 +        call[i].args[arg++] = pte.pte_high;
   2.128 +#endif  
   2.129 +        call[i].args[arg++] = UVMF_INVLPG;
   2.130 +    }
   2.131 +    ret = HYPERVISOR_multicall(call, i);
   2.132 +    if ( ret )
   2.133 +    {
   2.134 +        printk("update_va_mapping hypercall no. 2 failed with rc=%d.\n", ret);
   2.135 +        return 0;
   2.136 +    }
   2.137 +
   2.138 +    if ( !exch_success )
   2.139 +    {
   2.140 +        /* since the exchanged failed we just free the pages as well */
   2.141 +        free_pages((void *) in_va, order);
   2.142 +        return 0;
   2.143 +    }
   2.144 +    
   2.145 +    return in_va;
   2.146 +}
   2.147 +
   2.148 +/*
   2.149   * Check if a given MFN refers to real memory
   2.150   */
   2.151  static long system_ram_end_mfn;
     3.1 --- a/extras/mini-os/include/mm.h	Thu Mar 12 18:48:09 2009 +0000
     3.2 +++ b/extras/mini-os/include/mm.h	Fri Mar 13 07:37:24 2009 +0000
     3.3 @@ -72,6 +72,7 @@ void do_map_frames(unsigned long addr,
     3.4          unsigned long *f, unsigned long n, unsigned long stride,
     3.5  	unsigned long increment, domid_t id, int may_fail, unsigned long prot);
     3.6  int unmap_frames(unsigned long va, unsigned long num_frames);
     3.7 +unsigned long alloc_contig_pages(int order, unsigned int addr_bits);
     3.8  #ifdef HAVE_LIBC
     3.9  extern unsigned long heap, brk, heap_mapped, heap_end;
    3.10  #endif
     4.1 --- a/extras/mini-os/include/x86/arch_mm.h	Thu Mar 12 18:48:09 2009 +0000
     4.2 +++ b/extras/mini-os/include/x86/arch_mm.h	Fri Mar 13 07:37:24 2009 +0000
     4.3 @@ -137,6 +137,9 @@ typedef unsigned long pgentry_t;
     4.4  #define IO_PROT (L1_PROT)
     4.5  #define IO_PROT_NOCACHE (L1_PROT | _PAGE_PCD)
     4.6  
     4.7 +/* for P2M */
     4.8 +#define INVALID_P2M_ENTRY (~0UL)
     4.9 +
    4.10  #include "arch_limits.h"
    4.11  #define PAGE_SIZE       __PAGE_SIZE
    4.12  #define PAGE_SHIFT      __PAGE_SHIFT