ia64/xen-unstable

annotate xen/common/memory.c @ 8688:990c009015e8

Merge up and generally make shadow mode be nice.

Signed-off-by: Steven Smith, sos22@cam.ac.uk
author sos22@douglas.cl.cam.ac.uk
date Fri Jan 27 21:23:06 2006 +0100 (2006-01-27)
parents 1580009f137c 17dc21008351
children a47b7a464f09
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@8673 33 unsigned long 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 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@6701 61 if ( (extent_list != NULL) &&
kaf24@6701 62 (__put_user(page_to_pfn(page), &extent_list[i]) != 0) )
kaf24@6486 63 return i;
kaf24@6486 64 }
kaf24@6486 65
kaf24@6486 66 return nr_extents;
kaf24@6486 67 }
sos22@8688 68
kaf24@6486 69 static long
kaf24@8673 70 populate_physmap(
kaf24@8673 71 struct domain *d,
kaf24@8673 72 unsigned long *extent_list,
kaf24@8673 73 unsigned int nr_extents,
kaf24@8673 74 unsigned int extent_order,
kaf24@8673 75 unsigned int flags,
kaf24@8673 76 int *preempted)
kaf24@8673 77 {
sos22@8688 78 struct pfn_info *page;
sos22@8688 79 unsigned long i, j, pfn, mfn;
sos22@8688 80 struct domain_mmap_cache cache1, cache2;
kaf24@8673 81
kaf24@8673 82 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@8673 83 return 0;
kaf24@8673 84
kaf24@8673 85 if ( (extent_order != 0) &&
kaf24@8673 86 !multipage_allocation_permitted(current->domain) )
kaf24@8673 87 return 0;
kaf24@8673 88
sos22@8688 89 if (shadow_mode_translate(d)) {
sos22@8688 90 domain_mmap_cache_init(&cache1);
sos22@8688 91 domain_mmap_cache_init(&cache2);
sos22@8688 92 shadow_lock(d);
sos22@8688 93 }
sos22@8688 94
kaf24@8673 95 for ( i = 0; i < nr_extents; i++ )
kaf24@8673 96 {
kaf24@8673 97 if ( hypercall_preempt_check() )
kaf24@8673 98 {
kaf24@8673 99 *preempted = 1;
sos22@8688 100 goto out;
kaf24@8673 101 }
kaf24@8673 102
kaf24@8673 103 if ( unlikely((page = alloc_domheap_pages(
kaf24@8673 104 d, extent_order, flags)) == NULL) )
kaf24@8673 105 {
kaf24@8673 106 DPRINTK("Could not allocate order=%d extent: "
kaf24@8673 107 "id=%d flags=%x (%ld of %d)\n",
kaf24@8673 108 extent_order, d->domain_id, flags, i, nr_extents);
sos22@8688 109 goto out;
kaf24@8673 110 }
kaf24@8673 111
kaf24@8673 112 mfn = page_to_pfn(page);
kaf24@8673 113
kaf24@8673 114 if ( unlikely(__get_user(pfn, &extent_list[i]) != 0) )
sos22@8688 115 goto out;
kaf24@8673 116
sos22@8688 117 for ( j = 0; j < (1 << extent_order); j++ ) {
sos22@8688 118 printf("Populating %lx with %lx.\n",
sos22@8688 119 pfn + j, mfn + j);
sos22@8688 120 if (shadow_mode_translate(d))
sos22@8688 121 set_p2m_entry(d, pfn + j, mfn + j, &cache1, &cache2);
kaf24@8673 122 set_pfn_from_mfn(mfn + j, pfn + j);
sos22@8688 123 }
kaf24@8673 124
sos22@8688 125 if (!shadow_mode_translate(d)) {
sos22@8688 126 /* Inform the domain of the new page's machine address. */
sos22@8688 127 if ( __put_user(mfn, &extent_list[i]) != 0 )
sos22@8688 128 goto out;
sos22@8688 129 }
kaf24@8673 130 }
kaf24@8673 131
sos22@8688 132 out:
sos22@8688 133 if (shadow_mode_translate(d)) {
sos22@8688 134 shadow_unlock(d);
sos22@8688 135 domain_mmap_cache_destroy(&cache1);
sos22@8688 136 domain_mmap_cache_destroy(&cache2);
sos22@8688 137 }
sos22@8688 138
sos22@8688 139 return i;
kaf24@8673 140 }
kaf24@8673 141
kaf24@8673 142 static long
kaf24@6486 143 decrease_reservation(
kaf24@6486 144 struct domain *d,
kaf24@6486 145 unsigned long *extent_list,
kaf24@6486 146 unsigned int nr_extents,
kaf24@6486 147 unsigned int extent_order,
kaf24@6607 148 unsigned int flags,
kaf24@6607 149 int *preempted)
kaf24@6486 150 {
kaf24@6486 151 struct pfn_info *page;
sos22@8688 152 unsigned long i, j, gpfn, mfn;
kaf24@6486 153
kaf24@6486 154 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
kaf24@6486 155 return 0;
kaf24@6486 156
kaf24@6486 157 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 158 {
kaf24@6486 159 if ( hypercall_preempt_check() )
kaf24@6607 160 {
kaf24@6607 161 *preempted = 1;
kaf24@6486 162 return i;
kaf24@6607 163 }
kaf24@6486 164
sos22@8688 165 if ( unlikely(__get_user(gpfn, &extent_list[i]) != 0) )
kaf24@6486 166 return i;
kaf24@6486 167
kaf24@6486 168 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@6486 169 {
sos22@8688 170 mfn = __gpfn_to_mfn(d, gpfn + j);
sos22@8682 171 if ( unlikely(mfn >= max_page) )
kaf24@6486 172 {
sos22@8688 173 DPRINTK("Domain %u page number out of range (%lx(%lx) >= %lx)\n",
sos22@8688 174 d->domain_id, mfn, gpfn, max_page);
kaf24@6486 175 return i;
kaf24@6486 176 }
kaf24@6486 177
sos22@8682 178 page = pfn_to_page(mfn);
kaf24@6486 179 if ( unlikely(!get_page(page, d)) )
kaf24@6486 180 {
kaf24@6486 181 DPRINTK("Bad page free for domain %u\n", d->domain_id);
kaf24@6486 182 return i;
kaf24@6486 183 }
kaf24@6486 184
kaf24@6486 185 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
kaf24@6486 186 put_page_and_type(page);
kaf24@6486 187
kaf24@6486 188 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
kaf24@6486 189 put_page(page);
kaf24@6486 190
sos22@8688 191 if (shadow_mode_translate(d)) {
sos22@8688 192 struct domain_mmap_cache c1, c2;
sos22@8688 193 domain_mmap_cache_init(&c1);
sos22@8688 194 domain_mmap_cache_init(&c2);
sos22@8688 195 shadow_lock(d);
sos22@8688 196 shadow_sync_and_drop_references(d, page);
sos22@8688 197 set_p2m_entry(d, gpfn + j, -1, &c1, &c2);
sos22@8688 198 set_pfn_from_mfn(mfn + j, INVALID_M2P_ENTRY);
sos22@8688 199 shadow_unlock(d);
sos22@8688 200 domain_mmap_cache_destroy(&c1);
sos22@8688 201 domain_mmap_cache_destroy(&c2);
sos22@8688 202 }
kaf24@6486 203 put_page(page);
kaf24@6486 204 }
kaf24@6486 205 }
kaf24@6486 206
kaf24@6486 207 return nr_extents;
kaf24@6486 208 }
kaf24@6486 209
kaf24@6486 210 /*
kaf24@6486 211 * To allow safe resume of do_memory_op() after preemption, we need to know
kaf24@6486 212 * at what point in the page list to resume. For this purpose I steal the
kaf24@6486 213 * high-order bits of the @cmd parameter, which are otherwise unused and zero.
kaf24@6486 214 */
kaf24@6486 215 #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
kaf24@6486 216
kaf24@6486 217 long do_memory_op(int cmd, void *arg)
kaf24@6486 218 {
kaf24@6486 219 struct domain *d;
kaf24@6607 220 int rc, start_extent, op, flags = 0, preempted = 0;
kaf24@6486 221 struct xen_memory_reservation reservation;
kaf24@7959 222 domid_t domid;
kaf24@6486 223
kaf24@6486 224 op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
kaf24@6486 225
kaf24@6486 226 switch ( op )
kaf24@6486 227 {
kaf24@6486 228 case XENMEM_increase_reservation:
kaf24@6486 229 case XENMEM_decrease_reservation:
kaf24@8673 230 case XENMEM_populate_physmap:
kaf24@6486 231 if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
kaf24@6486 232 return -EFAULT;
kaf24@6486 233
kaf24@6486 234 start_extent = cmd >> START_EXTENT_SHIFT;
kaf24@6486 235 if ( unlikely(start_extent > reservation.nr_extents) )
kaf24@6486 236 return -EINVAL;
kaf24@6486 237
kaf24@6486 238 if ( reservation.extent_start != NULL )
kaf24@6486 239 reservation.extent_start += start_extent;
kaf24@6486 240 reservation.nr_extents -= start_extent;
kaf24@6486 241
kaf24@6701 242 if ( (reservation.address_bits != 0) &&
kaf24@6702 243 (reservation.address_bits <
kaf24@6702 244 (get_order_from_pages(max_page) + PAGE_SHIFT)) )
kaf24@6486 245 {
kaf24@6486 246 if ( reservation.address_bits < 31 )
kaf24@6486 247 return -ENOMEM;
kaf24@6486 248 flags = ALLOC_DOM_DMA;
kaf24@6486 249 }
kaf24@6486 250
kaf24@6486 251 if ( likely(reservation.domid == DOMID_SELF) )
kaf24@6486 252 d = current->domain;
kaf24@6486 253 else if ( !IS_PRIV(current->domain) )
kaf24@6486 254 return -EPERM;
kaf24@6486 255 else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
kaf24@6486 256 return -ESRCH;
kaf24@6486 257
kaf24@8673 258 switch ( op )
kaf24@8673 259 {
kaf24@8673 260 case XENMEM_increase_reservation:
kaf24@8673 261 rc = increase_reservation(
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 case XENMEM_decrease_reservation:
kaf24@8673 270 rc = decrease_reservation(
kaf24@8673 271 d,
kaf24@8673 272 reservation.extent_start,
kaf24@8673 273 reservation.nr_extents,
kaf24@8673 274 reservation.extent_order,
kaf24@8673 275 flags,
kaf24@8673 276 &preempted);
kaf24@8673 277 break;
kaf24@8673 278 case XENMEM_populate_physmap:
kaf24@8673 279 default:
kaf24@8673 280 rc = populate_physmap(
kaf24@8673 281 d,
kaf24@8673 282 reservation.extent_start,
kaf24@8673 283 reservation.nr_extents,
kaf24@8673 284 reservation.extent_order,
kaf24@8673 285 flags,
kaf24@8673 286 &preempted);
kaf24@8673 287 break;
kaf24@8673 288 }
kaf24@6486 289
kaf24@6486 290 if ( unlikely(reservation.domid != DOMID_SELF) )
kaf24@6486 291 put_domain(d);
kaf24@6486 292
kaf24@6486 293 rc += start_extent;
kaf24@6486 294
kaf24@6607 295 if ( preempted )
kaf24@6486 296 return hypercall2_create_continuation(
kaf24@6607 297 __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg);
kaf24@6607 298
kaf24@6486 299 break;
kaf24@6486 300
kaf24@6486 301 case XENMEM_maximum_ram_page:
kaf24@7959 302 rc = max_page;
kaf24@7959 303 break;
kaf24@7959 304
kaf24@7959 305 case XENMEM_current_reservation:
kaf24@7959 306 case XENMEM_maximum_reservation:
kaf24@7959 307 if ( get_user(domid, (domid_t *)arg) )
kaf24@6486 308 return -EFAULT;
kaf24@7959 309
kaf24@7959 310 if ( likely((domid = (unsigned long)arg) == DOMID_SELF) )
kaf24@7959 311 d = current->domain;
kaf24@7959 312 else if ( !IS_PRIV(current->domain) )
kaf24@7959 313 return -EPERM;
kaf24@7959 314 else if ( (d = find_domain_by_id(domid)) == NULL )
kaf24@7959 315 return -ESRCH;
kaf24@7959 316
kaf24@7959 317 rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
kaf24@7959 318
kaf24@7959 319 if ( unlikely(domid != DOMID_SELF) )
kaf24@7959 320 put_domain(d);
kaf24@7959 321
kaf24@6486 322 break;
kaf24@6486 323
kaf24@6486 324 default:
kaf24@8059 325 rc = arch_memory_op(op, arg);
kaf24@6486 326 break;
kaf24@6486 327 }
kaf24@6486 328
kaf24@6486 329 return rc;
kaf24@6486 330 }
kaf24@6486 331
kaf24@6486 332 /*
kaf24@6486 333 * Local variables:
kaf24@6486 334 * mode: C
kaf24@6486 335 * c-set-style: "BSD"
kaf24@6486 336 * c-basic-offset: 4
kaf24@6486 337 * tab-width: 4
kaf24@6486 338 * indent-tabs-mode: nil
kaf24@6486 339 * End:
kaf24@6486 340 */