ia64/xen-unstable

annotate xen/common/memory.c @ 8859:1346a69694be

Clean up grant-table code and replace uses of get_user
and put_user in common code. This is an attempt to narrow
the uaccess API before it gets replaced.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Feb 15 15:20:32 2006 +0100 (2006-02-15)
parents 8aeb417387ca
children 0d10fac28427
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@8726 32 struct page_info *page;
kaf24@8859 33 unsigned long i, mfn;
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 return 0;
kaf24@6486 42
kaf24@6486 43 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 44 {
kaf24@6486 45 if ( hypercall_preempt_check() )
kaf24@6607 46 {
kaf24@6607 47 *preempted = 1;
kaf24@6486 48 return i;
kaf24@6607 49 }
kaf24@6486 50
kaf24@6486 51 if ( unlikely((page = alloc_domheap_pages(
kaf24@6486 52 d, extent_order, flags)) == NULL) )
kaf24@6486 53 {
kaf24@6752 54 DPRINTK("Could not allocate order=%d extent: "
kaf24@8673 55 "id=%d flags=%x (%ld of %d)\n",
kaf24@6752 56 extent_order, d->domain_id, flags, i, nr_extents);
kaf24@6486 57 return i;
kaf24@6486 58 }
kaf24@6486 59
kaf24@6486 60 /* Inform the domain of the new page's machine address. */
kaf24@8859 61 if ( extent_list != NULL )
kaf24@8859 62 {
kaf24@8859 63 mfn = page_to_mfn(page);
kaf24@8859 64 if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) )
kaf24@8859 65 return i;
kaf24@8859 66 }
kaf24@6486 67 }
kaf24@6486 68
kaf24@6486 69 return nr_extents;
kaf24@6486 70 }
sos22@8688 71
kaf24@6486 72 static long
kaf24@8673 73 populate_physmap(
kaf24@8673 74 struct domain *d,
kaf24@8673 75 unsigned long *extent_list,
kaf24@8673 76 unsigned int nr_extents,
kaf24@8673 77 unsigned int extent_order,
kaf24@8673 78 unsigned int flags,
kaf24@8673 79 int *preempted)
kaf24@8673 80 {
kaf24@8726 81 struct page_info *page;
kaf24@8736 82 unsigned long i, j, gpfn, mfn;
kaf24@8673 83
kaf24@8673 84 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@8673 85 return 0;
kaf24@8673 86
kaf24@8673 87 if ( (extent_order != 0) &&
kaf24@8673 88 !multipage_allocation_permitted(current->domain) )
kaf24@8673 89 return 0;
kaf24@8673 90
kaf24@8673 91 for ( i = 0; i < nr_extents; i++ )
kaf24@8673 92 {
kaf24@8673 93 if ( hypercall_preempt_check() )
kaf24@8673 94 {
kaf24@8673 95 *preempted = 1;
sos22@8688 96 goto out;
kaf24@8673 97 }
kaf24@8673 98
kaf24@8859 99 if ( unlikely(__copy_from_user(&gpfn, &extent_list[i], sizeof(gpfn))) )
kaf24@8859 100 goto out;
kaf24@8859 101
kaf24@8673 102 if ( unlikely((page = alloc_domheap_pages(
kaf24@8673 103 d, extent_order, flags)) == NULL) )
kaf24@8673 104 {
kaf24@8673 105 DPRINTK("Could not allocate order=%d extent: "
kaf24@8673 106 "id=%d flags=%x (%ld of %d)\n",
kaf24@8673 107 extent_order, d->domain_id, flags, i, nr_extents);
sos22@8688 108 goto out;
kaf24@8673 109 }
kaf24@8673 110
kaf24@8726 111 mfn = page_to_mfn(page);
kaf24@8673 112
kaf24@8694 113 if ( unlikely(shadow_mode_translate(d)) )
kaf24@8694 114 {
kaf24@8694 115 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@8736 116 guest_physmap_add_page(d, gpfn + j, mfn + j);
sos22@8688 117 }
kaf24@8694 118 else
kaf24@8694 119 {
kaf24@8694 120 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@8736 121 set_gpfn_from_mfn(mfn + j, gpfn + j);
kaf24@8673 122
sos22@8688 123 /* Inform the domain of the new page's machine address. */
kaf24@8859 124 if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) )
sos22@8688 125 goto out;
sos22@8688 126 }
kaf24@8673 127 }
kaf24@8673 128
sos22@8688 129 out:
sos22@8688 130 return i;
kaf24@8673 131 }
kaf24@8673 132
kaf24@8673 133 static long
kaf24@6486 134 decrease_reservation(
kaf24@6486 135 struct domain *d,
kaf24@6486 136 unsigned long *extent_list,
kaf24@6486 137 unsigned int nr_extents,
kaf24@6486 138 unsigned int extent_order,
kaf24@6607 139 unsigned int flags,
kaf24@6607 140 int *preempted)
kaf24@6486 141 {
kaf24@8726 142 struct page_info *page;
kaf24@8726 143 unsigned long i, j, gmfn, mfn;
kaf24@6486 144
kaf24@6486 145 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@6486 146 return 0;
kaf24@6486 147
kaf24@6486 148 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 149 {
kaf24@6486 150 if ( hypercall_preempt_check() )
kaf24@6607 151 {
kaf24@6607 152 *preempted = 1;
kaf24@6486 153 return i;
kaf24@6607 154 }
kaf24@6486 155
kaf24@8859 156 if ( unlikely(__copy_from_user(&gmfn, &extent_list[i], sizeof(gmfn))) )
kaf24@6486 157 return i;
kaf24@6486 158
kaf24@6486 159 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@6486 160 {
kaf24@8726 161 mfn = gmfn_to_mfn(d, gmfn + j);
kaf24@8736 162 if ( unlikely(!mfn_valid(mfn)) )
kaf24@6486 163 {
kaf24@8736 164 DPRINTK("Domain %u page number %lx invalid\n",
kaf24@8736 165 d->domain_id, mfn);
kaf24@6486 166 return i;
kaf24@6486 167 }
kaf24@6486 168
kaf24@8726 169 page = mfn_to_page(mfn);
kaf24@6486 170 if ( unlikely(!get_page(page, d)) )
kaf24@6486 171 {
kaf24@6486 172 DPRINTK("Bad page free for domain %u\n", d->domain_id);
kaf24@6486 173 return i;
kaf24@6486 174 }
kaf24@6486 175
kaf24@6486 176 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
kaf24@6486 177 put_page_and_type(page);
kaf24@6486 178
kaf24@6486 179 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
kaf24@6486 180 put_page(page);
kaf24@6486 181
kaf24@8726 182 guest_physmap_remove_page(d, gmfn + j, mfn);
kaf24@8694 183
kaf24@6486 184 put_page(page);
kaf24@6486 185 }
kaf24@6486 186 }
kaf24@6486 187
kaf24@6486 188 return nr_extents;
kaf24@6486 189 }
kaf24@6486 190
kaf24@6486 191 /*
kaf24@6486 192 * To allow safe resume of do_memory_op() after preemption, we need to know
kaf24@6486 193 * at what point in the page list to resume. For this purpose I steal the
kaf24@6486 194 * high-order bits of the @cmd parameter, which are otherwise unused and zero.
kaf24@6486 195 */
kaf24@6486 196 #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
kaf24@6486 197
kaf24@6486 198 long do_memory_op(int cmd, void *arg)
kaf24@6486 199 {
kaf24@6486 200 struct domain *d;
kaf24@6607 201 int rc, start_extent, op, flags = 0, preempted = 0;
kaf24@6486 202 struct xen_memory_reservation reservation;
kaf24@7959 203 domid_t domid;
kaf24@6486 204
kaf24@6486 205 op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
kaf24@6486 206
kaf24@6486 207 switch ( op )
kaf24@6486 208 {
kaf24@6486 209 case XENMEM_increase_reservation:
kaf24@6486 210 case XENMEM_decrease_reservation:
kaf24@8673 211 case XENMEM_populate_physmap:
kaf24@6486 212 if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
kaf24@6486 213 return -EFAULT;
kaf24@6486 214
kaf24@6486 215 start_extent = cmd >> START_EXTENT_SHIFT;
kaf24@6486 216 if ( unlikely(start_extent > reservation.nr_extents) )
kaf24@6486 217 return -EINVAL;
kaf24@6486 218
kaf24@6486 219 if ( reservation.extent_start != NULL )
kaf24@6486 220 reservation.extent_start += start_extent;
kaf24@6486 221 reservation.nr_extents -= start_extent;
kaf24@6486 222
kaf24@6701 223 if ( (reservation.address_bits != 0) &&
kaf24@6702 224 (reservation.address_bits <
kaf24@6702 225 (get_order_from_pages(max_page) + PAGE_SHIFT)) )
kaf24@6486 226 {
kaf24@6486 227 if ( reservation.address_bits < 31 )
kaf24@6486 228 return -ENOMEM;
kaf24@6486 229 flags = ALLOC_DOM_DMA;
kaf24@6486 230 }
kaf24@6486 231
kaf24@6486 232 if ( likely(reservation.domid == DOMID_SELF) )
kaf24@6486 233 d = current->domain;
kaf24@6486 234 else if ( !IS_PRIV(current->domain) )
kaf24@6486 235 return -EPERM;
kaf24@6486 236 else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
kaf24@6486 237 return -ESRCH;
kaf24@6486 238
kaf24@8673 239 switch ( op )
kaf24@8673 240 {
kaf24@8673 241 case XENMEM_increase_reservation:
kaf24@8673 242 rc = increase_reservation(
kaf24@8673 243 d,
kaf24@8673 244 reservation.extent_start,
kaf24@8673 245 reservation.nr_extents,
kaf24@8673 246 reservation.extent_order,
kaf24@8673 247 flags,
kaf24@8673 248 &preempted);
kaf24@8673 249 break;
kaf24@8673 250 case XENMEM_decrease_reservation:
kaf24@8673 251 rc = decrease_reservation(
kaf24@8673 252 d,
kaf24@8673 253 reservation.extent_start,
kaf24@8673 254 reservation.nr_extents,
kaf24@8673 255 reservation.extent_order,
kaf24@8673 256 flags,
kaf24@8673 257 &preempted);
kaf24@8673 258 break;
kaf24@8673 259 case XENMEM_populate_physmap:
kaf24@8673 260 default:
kaf24@8673 261 rc = populate_physmap(
kaf24@8673 262 d,
kaf24@8673 263 reservation.extent_start,
kaf24@8673 264 reservation.nr_extents,
kaf24@8673 265 reservation.extent_order,
kaf24@8673 266 flags,
kaf24@8673 267 &preempted);
kaf24@8673 268 break;
kaf24@8673 269 }
kaf24@6486 270
kaf24@6486 271 if ( unlikely(reservation.domid != DOMID_SELF) )
kaf24@6486 272 put_domain(d);
kaf24@6486 273
kaf24@6486 274 rc += start_extent;
kaf24@6486 275
kaf24@6607 276 if ( preempted )
kaf24@6486 277 return hypercall2_create_continuation(
kaf24@6607 278 __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg);
kaf24@6607 279
kaf24@6486 280 break;
kaf24@6486 281
kaf24@6486 282 case XENMEM_maximum_ram_page:
kaf24@7959 283 rc = max_page;
kaf24@7959 284 break;
kaf24@7959 285
kaf24@7959 286 case XENMEM_current_reservation:
kaf24@7959 287 case XENMEM_maximum_reservation:
kaf24@8859 288 if ( copy_from_user(&domid, (domid_t *)arg, sizeof(domid)) )
kaf24@6486 289 return -EFAULT;
kaf24@7959 290
kaf24@7959 291 if ( likely((domid = (unsigned long)arg) == DOMID_SELF) )
kaf24@7959 292 d = current->domain;
kaf24@7959 293 else if ( !IS_PRIV(current->domain) )
kaf24@7959 294 return -EPERM;
kaf24@7959 295 else if ( (d = find_domain_by_id(domid)) == NULL )
kaf24@7959 296 return -ESRCH;
kaf24@7959 297
kaf24@7959 298 rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
kaf24@7959 299
kaf24@7959 300 if ( unlikely(domid != DOMID_SELF) )
kaf24@7959 301 put_domain(d);
kaf24@7959 302
kaf24@6486 303 break;
kaf24@6486 304
kaf24@6486 305 default:
kaf24@8059 306 rc = arch_memory_op(op, arg);
kaf24@6486 307 break;
kaf24@6486 308 }
kaf24@6486 309
kaf24@6486 310 return rc;
kaf24@6486 311 }
kaf24@6486 312
kaf24@6486 313 /*
kaf24@6486 314 * Local variables:
kaf24@6486 315 * mode: C
kaf24@6486 316 * c-set-style: "BSD"
kaf24@6486 317 * c-basic-offset: 4
kaf24@6486 318 * tab-width: 4
kaf24@6486 319 * indent-tabs-mode: nil
kaf24@6486 320 * End:
kaf24@6486 321 */