ia64/xen-unstable

view xen/common/memory.c @ 7959:ff18a169e866

Update the memory_op() hypercall. Add two new subcommands, to
query a domain's current and maximum memory reservation. Also,
XENMEM_maximum_ram_page now returns the max_page directly,
rather than writing through a passed-in pointer.

Also, disable PAE in the default config (accidentally checked
in two changesets ago).

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