ia64/xen-unstable

annotate xen/common/memory.c @ 9211:fbeb0a5b7219

Change the location of the shared_info page for auto_translated_physmap guests.
Instead of putting the page outside of the guests pseudo-physical address
space, we put it next to the other pages filled by the domain builder,
such that the page is already mapped in the initial pagetables and/or a
lowmem-type memory mapping.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Mar 09 16:24:57 2006 +0000 (2006-03-09)
parents 2307bf2a4bfc
children 4e1b8be54311
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@9068 19 #include <xen/guest_access.h>
kaf24@6486 20 #include <asm/current.h>
kaf24@6486 21 #include <asm/hardirq.h>
kaf24@6486 22 #include <public/memory.h>
kaf24@6486 23
kaf24@8871 24 /*
kaf24@8871 25 * To allow safe resume of do_memory_op() after preemption, we need to know
kaf24@8871 26 * at what point in the page list to resume. For this purpose I steal the
kaf24@8871 27 * high-order bits of the @cmd parameter, which are otherwise unused and zero.
kaf24@8871 28 */
kaf24@8871 29 #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
kaf24@8871 30
kaf24@6486 31 static long
kaf24@6486 32 increase_reservation(
kaf24@6486 33 struct domain *d,
kaf24@9136 34 GUEST_HANDLE(ulong) extent_list,
kaf24@6486 35 unsigned int nr_extents,
kaf24@6486 36 unsigned int extent_order,
kaf24@6607 37 unsigned int flags,
kaf24@6607 38 int *preempted)
kaf24@6486 39 {
kaf24@8726 40 struct page_info *page;
kaf24@8859 41 unsigned long i, mfn;
kaf24@6486 42
kaf24@9068 43 if ( !guest_handle_is_null(extent_list) &&
kaf24@9068 44 !guest_handle_okay(extent_list, nr_extents) )
kaf24@6486 45 return 0;
kaf24@6486 46
kaf24@8468 47 if ( (extent_order != 0) &&
kaf24@8468 48 !multipage_allocation_permitted(current->domain) )
kaf24@6486 49 return 0;
kaf24@6486 50
kaf24@6486 51 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 52 {
kaf24@6486 53 if ( hypercall_preempt_check() )
kaf24@6607 54 {
kaf24@6607 55 *preempted = 1;
kaf24@6486 56 return i;
kaf24@6607 57 }
kaf24@6486 58
kaf24@6486 59 if ( unlikely((page = alloc_domheap_pages(
kaf24@6486 60 d, extent_order, flags)) == NULL) )
kaf24@6486 61 {
kaf24@6752 62 DPRINTK("Could not allocate order=%d extent: "
kaf24@8673 63 "id=%d flags=%x (%ld of %d)\n",
kaf24@6752 64 extent_order, d->domain_id, flags, i, nr_extents);
kaf24@6486 65 return i;
kaf24@6486 66 }
kaf24@6486 67
kaf24@6486 68 /* Inform the domain of the new page's machine address. */
kaf24@9068 69 if ( !guest_handle_is_null(extent_list) )
kaf24@8859 70 {
kaf24@8859 71 mfn = page_to_mfn(page);
kaf24@9068 72 if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
kaf24@8859 73 return i;
kaf24@8859 74 }
kaf24@6486 75 }
kaf24@6486 76
kaf24@6486 77 return nr_extents;
kaf24@6486 78 }
sos22@8688 79
kaf24@6486 80 static long
kaf24@8673 81 populate_physmap(
kaf24@8673 82 struct domain *d,
kaf24@9136 83 GUEST_HANDLE(ulong) extent_list,
kaf24@9068 84 unsigned int nr_extents,
kaf24@9068 85 unsigned int extent_order,
kaf24@9068 86 unsigned int flags,
kaf24@9068 87 int *preempted)
kaf24@8673 88 {
kaf24@8726 89 struct page_info *page;
kaf24@8736 90 unsigned long i, j, gpfn, mfn;
kaf24@8673 91
kaf24@9068 92 if ( !guest_handle_okay(extent_list, nr_extents) )
kaf24@8673 93 return 0;
kaf24@8673 94
kaf24@8673 95 if ( (extent_order != 0) &&
kaf24@8673 96 !multipage_allocation_permitted(current->domain) )
kaf24@8673 97 return 0;
kaf24@8673 98
kaf24@8673 99 for ( i = 0; i < nr_extents; i++ )
kaf24@8673 100 {
kaf24@8673 101 if ( hypercall_preempt_check() )
kaf24@8673 102 {
kaf24@8673 103 *preempted = 1;
sos22@8688 104 goto out;
kaf24@8673 105 }
kaf24@8673 106
kaf24@9068 107 if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) )
kaf24@8859 108 goto out;
kaf24@8859 109
kaf24@8673 110 if ( unlikely((page = alloc_domheap_pages(
kaf24@8673 111 d, extent_order, flags)) == NULL) )
kaf24@8673 112 {
kaf24@8673 113 DPRINTK("Could not allocate order=%d extent: "
kaf24@8673 114 "id=%d flags=%x (%ld of %d)\n",
kaf24@8673 115 extent_order, d->domain_id, flags, i, nr_extents);
sos22@8688 116 goto out;
kaf24@8673 117 }
kaf24@8673 118
kaf24@8726 119 mfn = page_to_mfn(page);
kaf24@8673 120
kaf24@8694 121 if ( unlikely(shadow_mode_translate(d)) )
kaf24@8694 122 {
kaf24@8694 123 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@8736 124 guest_physmap_add_page(d, gpfn + j, mfn + j);
sos22@8688 125 }
kaf24@8694 126 else
kaf24@8694 127 {
kaf24@8694 128 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@8736 129 set_gpfn_from_mfn(mfn + j, gpfn + j);
kaf24@8673 130
sos22@8688 131 /* Inform the domain of the new page's machine address. */
kaf24@9068 132 if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
sos22@8688 133 goto out;
sos22@8688 134 }
kaf24@8673 135 }
kaf24@8673 136
sos22@8688 137 out:
sos22@8688 138 return i;
kaf24@8673 139 }
cl349@9211 140
cl349@9211 141 int
cl349@9211 142 guest_remove_page(
cl349@9211 143 struct domain *d,
cl349@9211 144 unsigned long gmfn)
cl349@9211 145 {
cl349@9211 146 struct page_info *page;
cl349@9211 147 unsigned long mfn;
cl349@9211 148
cl349@9211 149 mfn = gmfn_to_mfn(d, gmfn);
cl349@9211 150 if ( unlikely(!mfn_valid(mfn)) )
cl349@9211 151 {
cl349@9211 152 DPRINTK("Domain %u page number %lx invalid\n",
cl349@9211 153 d->domain_id, mfn);
cl349@9211 154 return 0;
cl349@9211 155 }
cl349@9211 156
cl349@9211 157 page = mfn_to_page(mfn);
cl349@9211 158 if ( unlikely(!get_page(page, d)) )
cl349@9211 159 {
cl349@9211 160 DPRINTK("Bad page free for domain %u\n", d->domain_id);
cl349@9211 161 return 0;
cl349@9211 162 }
cl349@9211 163
cl349@9211 164 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
cl349@9211 165 put_page_and_type(page);
cl349@9211 166
cl349@9211 167 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
cl349@9211 168 put_page(page);
cl349@9211 169
cl349@9211 170 guest_physmap_remove_page(d, gmfn, mfn);
cl349@9211 171
cl349@9211 172 put_page(page);
cl349@9211 173
cl349@9211 174 return 1;
cl349@9211 175 }
cl349@9211 176
kaf24@8673 177 static long
kaf24@6486 178 decrease_reservation(
kaf24@9068 179 struct domain *d,
kaf24@9136 180 GUEST_HANDLE(ulong) extent_list,
kaf24@6486 181 unsigned int nr_extents,
kaf24@6486 182 unsigned int extent_order,
kaf24@6607 183 unsigned int flags,
kaf24@6607 184 int *preempted)
kaf24@6486 185 {
cl349@9211 186 unsigned long i, j, gmfn;
kaf24@6486 187
kaf24@9068 188 if ( !guest_handle_okay(extent_list, nr_extents) )
kaf24@6486 189 return 0;
kaf24@6486 190
kaf24@6486 191 for ( i = 0; i < nr_extents; i++ )
kaf24@6486 192 {
kaf24@6486 193 if ( hypercall_preempt_check() )
kaf24@6607 194 {
kaf24@6607 195 *preempted = 1;
kaf24@6486 196 return i;
kaf24@6607 197 }
kaf24@6486 198
kaf24@9068 199 if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) )
kaf24@6486 200 return i;
kaf24@6486 201
kaf24@6486 202 for ( j = 0; j < (1 << extent_order); j++ )
kaf24@6486 203 {
cl349@9211 204 if ( !guest_remove_page(d, gmfn + j) )
kaf24@6486 205 return i;
kaf24@6486 206 }
kaf24@6486 207 }
kaf24@6486 208
kaf24@6486 209 return nr_extents;
kaf24@6486 210 }
kaf24@6486 211
kaf24@8871 212 static long
kaf24@8871 213 translate_gpfn_list(
kaf24@9136 214 GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress)
kaf24@8871 215 {
kaf24@8871 216 struct xen_translate_gpfn_list op;
kaf24@8871 217 unsigned long i, gpfn, mfn;
kaf24@8871 218 struct domain *d;
kaf24@6486 219
kaf24@9068 220 if ( copy_from_guest(&op, uop, 1) )
kaf24@8871 221 return -EFAULT;
kaf24@8871 222
kaf24@8871 223 /* Is size too large for us to encode a continuation? */
kaf24@8871 224 if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) )
kaf24@8871 225 return -EINVAL;
kaf24@8871 226
kaf24@9068 227 if ( !guest_handle_okay(op.gpfn_list, op.nr_gpfns) ||
kaf24@9068 228 !guest_handle_okay(op.mfn_list, op.nr_gpfns) )
kaf24@8871 229 return -EFAULT;
kaf24@8871 230
kaf24@8871 231 if ( op.domid == DOMID_SELF )
kaf24@8871 232 op.domid = current->domain->domain_id;
kaf24@8871 233 else if ( !IS_PRIV(current->domain) )
kaf24@8871 234 return -EPERM;
kaf24@8871 235
kaf24@8871 236 if ( (d = find_domain_by_id(op.domid)) == NULL )
kaf24@8871 237 return -ESRCH;
kaf24@8871 238
kaf24@8871 239 if ( !shadow_mode_translate(d) )
kaf24@8871 240 {
kaf24@8871 241 put_domain(d);
kaf24@8871 242 return -EINVAL;
kaf24@8871 243 }
kaf24@8871 244
kaf24@8871 245 for ( i = *progress; i < op.nr_gpfns; i++ )
kaf24@8871 246 {
kaf24@8871 247 if ( hypercall_preempt_check() )
kaf24@8871 248 {
kaf24@8871 249 put_domain(d);
kaf24@8871 250 *progress = i;
kaf24@8871 251 return -EAGAIN;
kaf24@8871 252 }
kaf24@8871 253
kaf24@9068 254 if ( unlikely(__copy_from_guest_offset(&gpfn, op.gpfn_list, i, 1)) )
kaf24@8871 255 {
kaf24@8871 256 put_domain(d);
kaf24@8871 257 return -EFAULT;
kaf24@8871 258 }
kaf24@8871 259
kaf24@8871 260 mfn = gmfn_to_mfn(d, gpfn);
kaf24@8871 261
kaf24@9068 262 if ( unlikely(__copy_to_guest_offset(op.mfn_list, i, &mfn, 1)) )
kaf24@8871 263 {
kaf24@8871 264 put_domain(d);
kaf24@8871 265 return -EFAULT;
kaf24@8871 266 }
kaf24@8871 267 }
kaf24@8871 268
kaf24@8871 269 put_domain(d);
kaf24@8871 270 return 0;
kaf24@8871 271 }
kaf24@8871 272
kaf24@9136 273 long do_memory_op(unsigned long cmd, GUEST_HANDLE(void) arg)
kaf24@6486 274 {
kaf24@6486 275 struct domain *d;
kaf24@8871 276 int rc, op, flags = 0, preempted = 0;
kaf24@8871 277 unsigned long start_extent, progress;
kaf24@6486 278 struct xen_memory_reservation reservation;
kaf24@7959 279 domid_t domid;
kaf24@6486 280
kaf24@6486 281 op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
kaf24@6486 282
kaf24@6486 283 switch ( op )
kaf24@6486 284 {
kaf24@6486 285 case XENMEM_increase_reservation:
kaf24@6486 286 case XENMEM_decrease_reservation:
kaf24@8673 287 case XENMEM_populate_physmap:
kaf24@9068 288 if ( copy_from_guest(&reservation, arg, 1) )
kaf24@6486 289 return -EFAULT;
kaf24@6486 290
kaf24@8871 291 /* Is size too large for us to encode a continuation? */
kaf24@8871 292 if ( reservation.nr_extents > (ULONG_MAX >> START_EXTENT_SHIFT) )
kaf24@8871 293 return -EINVAL;
kaf24@8871 294
kaf24@6486 295 start_extent = cmd >> START_EXTENT_SHIFT;
kaf24@6486 296 if ( unlikely(start_extent > reservation.nr_extents) )
kaf24@6486 297 return -EINVAL;
kaf24@9068 298
kaf24@9068 299 if ( !guest_handle_is_null(reservation.extent_start) )
kaf24@9068 300 guest_handle_add_offset(reservation.extent_start, start_extent);
kaf24@6486 301 reservation.nr_extents -= start_extent;
kaf24@6486 302
kaf24@6701 303 if ( (reservation.address_bits != 0) &&
kaf24@6702 304 (reservation.address_bits <
kaf24@6702 305 (get_order_from_pages(max_page) + PAGE_SHIFT)) )
kaf24@6486 306 {
kaf24@6486 307 if ( reservation.address_bits < 31 )
kaf24@6486 308 return -ENOMEM;
kaf24@6486 309 flags = ALLOC_DOM_DMA;
kaf24@6486 310 }
kaf24@6486 311
kaf24@6486 312 if ( likely(reservation.domid == DOMID_SELF) )
kaf24@6486 313 d = current->domain;
kaf24@6486 314 else if ( !IS_PRIV(current->domain) )
kaf24@6486 315 return -EPERM;
kaf24@6486 316 else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
kaf24@6486 317 return -ESRCH;
kaf24@6486 318
kaf24@8673 319 switch ( op )
kaf24@8673 320 {
kaf24@8673 321 case XENMEM_increase_reservation:
kaf24@8673 322 rc = increase_reservation(
kaf24@8673 323 d,
kaf24@8673 324 reservation.extent_start,
kaf24@8673 325 reservation.nr_extents,
kaf24@8673 326 reservation.extent_order,
kaf24@8673 327 flags,
kaf24@8673 328 &preempted);
kaf24@8673 329 break;
kaf24@8673 330 case XENMEM_decrease_reservation:
kaf24@8673 331 rc = decrease_reservation(
kaf24@8673 332 d,
kaf24@8673 333 reservation.extent_start,
kaf24@8673 334 reservation.nr_extents,
kaf24@8673 335 reservation.extent_order,
kaf24@8673 336 flags,
kaf24@8673 337 &preempted);
kaf24@8673 338 break;
kaf24@8673 339 case XENMEM_populate_physmap:
kaf24@8673 340 default:
kaf24@8673 341 rc = populate_physmap(
kaf24@8673 342 d,
kaf24@8673 343 reservation.extent_start,
kaf24@8673 344 reservation.nr_extents,
kaf24@8673 345 reservation.extent_order,
kaf24@8673 346 flags,
kaf24@8673 347 &preempted);
kaf24@8673 348 break;
kaf24@8673 349 }
kaf24@6486 350
kaf24@6486 351 if ( unlikely(reservation.domid != DOMID_SELF) )
kaf24@6486 352 put_domain(d);
kaf24@6486 353
kaf24@6486 354 rc += start_extent;
kaf24@6486 355
kaf24@6607 356 if ( preempted )
kaf24@9068 357 return hypercall_create_continuation(
kaf24@9068 358 __HYPERVISOR_memory_op, "lh",
kaf24@9068 359 op | (rc << START_EXTENT_SHIFT), arg);
kaf24@6607 360
kaf24@6486 361 break;
kaf24@6486 362
kaf24@6486 363 case XENMEM_maximum_ram_page:
kaf24@7959 364 rc = max_page;
kaf24@7959 365 break;
kaf24@7959 366
kaf24@7959 367 case XENMEM_current_reservation:
kaf24@7959 368 case XENMEM_maximum_reservation:
kaf24@9068 369 if ( copy_from_guest(&domid, arg, 1) )
kaf24@6486 370 return -EFAULT;
kaf24@7959 371
kaf24@9068 372 if ( likely(domid == DOMID_SELF) )
kaf24@7959 373 d = current->domain;
kaf24@7959 374 else if ( !IS_PRIV(current->domain) )
kaf24@7959 375 return -EPERM;
kaf24@7959 376 else if ( (d = find_domain_by_id(domid)) == NULL )
kaf24@7959 377 return -ESRCH;
kaf24@7959 378
kaf24@7959 379 rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
kaf24@7959 380
kaf24@7959 381 if ( unlikely(domid != DOMID_SELF) )
kaf24@7959 382 put_domain(d);
kaf24@7959 383
kaf24@6486 384 break;
kaf24@6486 385
kaf24@8871 386 case XENMEM_translate_gpfn_list:
kaf24@8871 387 progress = cmd >> START_EXTENT_SHIFT;
kaf24@9068 388 rc = translate_gpfn_list(
kaf24@9068 389 guest_handle_cast(arg, xen_translate_gpfn_list_t),
kaf24@9068 390 &progress);
kaf24@8871 391 if ( rc == -EAGAIN )
kaf24@9068 392 return hypercall_create_continuation(
kaf24@9068 393 __HYPERVISOR_memory_op, "lh",
kaf24@9068 394 op | (progress << START_EXTENT_SHIFT), arg);
kaf24@8871 395 break;
kaf24@8871 396
kaf24@6486 397 default:
kaf24@8059 398 rc = arch_memory_op(op, arg);
kaf24@6486 399 break;
kaf24@6486 400 }
kaf24@6486 401
kaf24@6486 402 return rc;
kaf24@6486 403 }
kaf24@6486 404
kaf24@6486 405 /*
kaf24@6486 406 * Local variables:
kaf24@6486 407 * mode: C
kaf24@6486 408 * c-set-style: "BSD"
kaf24@6486 409 * c-basic-offset: 4
kaf24@6486 410 * tab-width: 4
kaf24@6486 411 * indent-tabs-mode: nil
kaf24@6486 412 * End:
kaf24@6486 413 */