ia64/xen-unstable

annotate xen/common/memory.c @ 8468:d966b7a00959

Allow non-privileged domains restricted access to
I/O memory and physical interrupts, under control
of domain0. Capabilities are maintained as rangesets
in Xen.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Dec 31 14:15:22 2005 +0100 (2005-12-31)
parents 3d1c7be170a7
children 4520b451a70e
rev   line source
kaf24@6486 1 /******************************************************************************
kaf24@6486 2 * memory.c
kaf24@6486 3 *
kaf24@6486 4 * Code to handle memory-related requests.
kaf24@6486 5 *
kaf24@6486 6 * Copyright (c) 2003-2004, B Dragovic
kaf24@6486 7 * Copyright (c) 2003-2005, K A Fraser
kaf24@6486 8 */
kaf24@6486 9
kaf24@6486 10 #include <xen/config.h>
kaf24@6486 11 #include <xen/types.h>
kaf24@6486 12 #include <xen/lib.h>
kaf24@6486 13 #include <xen/mm.h>
kaf24@6486 14 #include <xen/perfc.h>
kaf24@6486 15 #include <xen/sched.h>
kaf24@6486 16 #include <xen/event.h>
kaf24@6486 17 #include <xen/shadow.h>
kaf24@8468 18 #include <xen/iocap.h>
kaf24@6486 19 #include <asm/current.h>
kaf24@6486 20 #include <asm/hardirq.h>
kaf24@6486 21 #include <public/memory.h>
kaf24@6486 22
kaf24@6486 23 static long
kaf24@6486 24 increase_reservation(
kaf24@6486 25 struct domain *d,
kaf24@6486 26 unsigned long *extent_list,
kaf24@6486 27 unsigned int nr_extents,
kaf24@6486 28 unsigned int extent_order,
kaf24@6607 29 unsigned int flags,
kaf24@6607 30 int *preempted)
kaf24@6486 31 {
kaf24@6486 32 struct pfn_info *page;
kaf24@6752 33 unsigned int i;
kaf24@6486 34
kaf24@6701 35 if ( (extent_list != NULL) &&
kaf24@6701 36 !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@6486 37 return 0;
kaf24@6486 38
kaf24@8468 39 if ( (extent_order != 0) &&
kaf24@8468 40 !multipage_allocation_permitted(current->domain) )
kaf24@6486 41 {
kaf24@6752 42 DPRINTK("Only I/O-capable domains may allocate multi-page extents.\n");
kaf24@6486 43 return 0;
kaf24@6486 44 }
kaf24@6486 45
kaf24@6486 46 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 47 {
kaf24@6486 48 if ( hypercall_preempt_check() )
kaf24@6607 49 {
kaf24@6607 50 *preempted = 1;
kaf24@6486 51 return i;
kaf24@6607 52 }
kaf24@6486 53
kaf24@6486 54 if ( unlikely((page = alloc_domheap_pages(
kaf24@6486 55 d, extent_order, flags)) == NULL) )
kaf24@6486 56 {
kaf24@6752 57 DPRINTK("Could not allocate order=%d extent: "
kaf24@6752 58 "id=%d flags=%x (%d of %d)\n",
kaf24@6752 59 extent_order, d->domain_id, flags, i, nr_extents);
kaf24@6486 60 return i;
kaf24@6486 61 }
kaf24@6486 62
kaf24@6486 63 /* Inform the domain of the new page's machine address. */
kaf24@6701 64 if ( (extent_list != NULL) &&
kaf24@6701 65 (__put_user(page_to_pfn(page), &extent_list[i]) != 0) )
kaf24@6486 66 return i;
kaf24@6486 67 }
kaf24@6486 68
kaf24@6486 69 return nr_extents;
kaf24@6486 70 }
kaf24@6486 71
kaf24@6486 72 static long
kaf24@6486 73 decrease_reservation(
kaf24@6486 74 struct domain *d,
kaf24@6486 75 unsigned long *extent_list,
kaf24@6486 76 unsigned int nr_extents,
kaf24@6486 77 unsigned int extent_order,
kaf24@6607 78 unsigned int flags,
kaf24@6607 79 int *preempted)
kaf24@6486 80 {
kaf24@6486 81 struct pfn_info *page;
kaf24@6486 82 unsigned long i, j, mpfn;
kaf24@6486 83
kaf24@6486 84 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@6486 85 return 0;
kaf24@6486 86
kaf24@6486 87 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 88 {
kaf24@6486 89 if ( hypercall_preempt_check() )
kaf24@6607 90 {
kaf24@6607 91 *preempted = 1;
kaf24@6486 92 return i;
kaf24@6607 93 }
kaf24@6486 94
kaf24@6486 95 if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) )
kaf24@6486 96 return i;
kaf24@6486 97
kaf24@6486 98 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@6486 99 {
kaf24@6486 100 if ( unlikely((mpfn + j) >= max_page) )
kaf24@6486 101 {
kaf24@6486 102 DPRINTK("Domain %u page number out of range (%lx >= %lx)\n",
kaf24@6486 103 d->domain_id, mpfn + j, max_page);
kaf24@6486 104 return i;
kaf24@6486 105 }
kaf24@6486 106
kaf24@8414 107 page = pfn_to_page(mpfn + j);
kaf24@6486 108 if ( unlikely(!get_page(page, d)) )
kaf24@6486 109 {
kaf24@6486 110 DPRINTK("Bad page free for domain %u\n", d->domain_id);
kaf24@6486 111 return i;
kaf24@6486 112 }
kaf24@6486 113
kaf24@6486 114 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
kaf24@6486 115 put_page_and_type(page);
kaf24@6486 116
kaf24@6486 117 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
kaf24@6486 118 put_page(page);
kaf24@6486 119
kaf24@6486 120 shadow_sync_and_drop_references(d, page);
kaf24@6486 121
kaf24@6486 122 put_page(page);
kaf24@6486 123 }
kaf24@6486 124 }
kaf24@6486 125
kaf24@6486 126 return nr_extents;
kaf24@6486 127 }
kaf24@6486 128
kaf24@6486 129 /*
kaf24@6486 130 * To allow safe resume of do_memory_op() after preemption, we need to know
kaf24@6486 131 * at what point in the page list to resume. For this purpose I steal the
kaf24@6486 132 * high-order bits of the @cmd parameter, which are otherwise unused and zero.
kaf24@6486 133 */
kaf24@6486 134 #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
kaf24@6486 135
kaf24@6486 136 long do_memory_op(int cmd, void *arg)
kaf24@6486 137 {
kaf24@6486 138 struct domain *d;
kaf24@6607 139 int rc, start_extent, op, flags = 0, preempted = 0;
kaf24@6486 140 struct xen_memory_reservation reservation;
kaf24@7959 141 domid_t domid;
kaf24@6486 142
kaf24@6486 143 op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
kaf24@6486 144
kaf24@6486 145 switch ( op )
kaf24@6486 146 {
kaf24@6486 147 case XENMEM_increase_reservation:
kaf24@6486 148 case XENMEM_decrease_reservation:
kaf24@6486 149 if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
kaf24@6486 150 return -EFAULT;
kaf24@6486 151
kaf24@6486 152 start_extent = cmd >> START_EXTENT_SHIFT;
kaf24@6486 153 if ( unlikely(start_extent > reservation.nr_extents) )
kaf24@6486 154 return -EINVAL;
kaf24@6486 155
kaf24@6486 156 if ( reservation.extent_start != NULL )
kaf24@6486 157 reservation.extent_start += start_extent;
kaf24@6486 158 reservation.nr_extents -= start_extent;
kaf24@6486 159
kaf24@6701 160 if ( (reservation.address_bits != 0) &&
kaf24@6702 161 (reservation.address_bits <
kaf24@6702 162 (get_order_from_pages(max_page) + PAGE_SHIFT)) )
kaf24@6486 163 {
kaf24@6486 164 if ( reservation.address_bits < 31 )
kaf24@6486 165 return -ENOMEM;
kaf24@6486 166 flags = ALLOC_DOM_DMA;
kaf24@6486 167 }
kaf24@6486 168
kaf24@6486 169 if ( likely(reservation.domid == DOMID_SELF) )
kaf24@6486 170 d = current->domain;
kaf24@6486 171 else if ( !IS_PRIV(current->domain) )
kaf24@6486 172 return -EPERM;
kaf24@6486 173 else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
kaf24@6486 174 return -ESRCH;
kaf24@6486 175
kaf24@6486 176 rc = ((op == XENMEM_increase_reservation) ?
kaf24@6486 177 increase_reservation : decrease_reservation)(
kaf24@6486 178 d,
kaf24@6486 179 reservation.extent_start,
kaf24@6486 180 reservation.nr_extents,
kaf24@6486 181 reservation.extent_order,
kaf24@6607 182 flags,
kaf24@6607 183 &preempted);
kaf24@6486 184
kaf24@6486 185 if ( unlikely(reservation.domid != DOMID_SELF) )
kaf24@6486 186 put_domain(d);
kaf24@6486 187
kaf24@6486 188 rc += start_extent;
kaf24@6486 189
kaf24@6607 190 if ( preempted )
kaf24@6486 191 return hypercall2_create_continuation(
kaf24@6607 192 __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg);
kaf24@6607 193
kaf24@6486 194 break;
kaf24@6486 195
kaf24@6486 196 case XENMEM_maximum_ram_page:
kaf24@7959 197 rc = max_page;
kaf24@7959 198 break;
kaf24@7959 199
kaf24@7959 200 case XENMEM_current_reservation:
kaf24@7959 201 case XENMEM_maximum_reservation:
kaf24@7959 202 if ( get_user(domid, (domid_t *)arg) )
kaf24@6486 203 return -EFAULT;
kaf24@7959 204
kaf24@7959 205 if ( likely((domid = (unsigned long)arg) == DOMID_SELF) )
kaf24@7959 206 d = current->domain;
kaf24@7959 207 else if ( !IS_PRIV(current->domain) )
kaf24@7959 208 return -EPERM;
kaf24@7959 209 else if ( (d = find_domain_by_id(domid)) == NULL )
kaf24@7959 210 return -ESRCH;
kaf24@7959 211
kaf24@7959 212 rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
kaf24@7959 213
kaf24@7959 214 if ( unlikely(domid != DOMID_SELF) )
kaf24@7959 215 put_domain(d);
kaf24@7959 216
kaf24@6486 217 break;
kaf24@6486 218
kaf24@6486 219 default:
kaf24@8059 220 rc = arch_memory_op(op, arg);
kaf24@6486 221 break;
kaf24@6486 222 }
kaf24@6486 223
kaf24@6486 224 return rc;
kaf24@6486 225 }
kaf24@6486 226
kaf24@6486 227 /*
kaf24@6486 228 * Local variables:
kaf24@6486 229 * mode: C
kaf24@6486 230 * c-set-style: "BSD"
kaf24@6486 231 * c-basic-offset: 4
kaf24@6486 232 * tab-width: 4
kaf24@6486 233 * indent-tabs-mode: nil
kaf24@6486 234 * End:
kaf24@6486 235 */