ia64/xen-unstable

view 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
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 <xen/iocap.h>
19 #include <asm/current.h>
20 #include <asm/hardirq.h>
21 #include <public/memory.h>
23 static long
24 increase_reservation(
25 struct domain *d,
26 unsigned long *extent_list,
27 unsigned int nr_extents,
28 unsigned int extent_order,
29 unsigned int flags,
30 int *preempted)
31 {
32 struct pfn_info *page;
33 unsigned int i;
35 if ( (extent_list != NULL) &&
36 !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
37 return 0;
39 if ( (extent_order != 0) &&
40 !multipage_allocation_permitted(current->domain) )
41 {
42 DPRINTK("Only I/O-capable domains may allocate multi-page extents.\n");
43 return 0;
44 }
46 for ( i = 0; i < nr_extents; i++ )
47 {
48 if ( hypercall_preempt_check() )
49 {
50 *preempted = 1;
51 return i;
52 }
54 if ( unlikely((page = alloc_domheap_pages(
55 d, extent_order, flags)) == NULL) )
56 {
57 DPRINTK("Could not allocate order=%d extent: "
58 "id=%d flags=%x (%d of %d)\n",
59 extent_order, d->domain_id, flags, i, nr_extents);
60 return i;
61 }
63 /* Inform the domain of the new page's machine address. */
64 if ( (extent_list != NULL) &&
65 (__put_user(page_to_pfn(page), &extent_list[i]) != 0) )
66 return i;
67 }
69 return nr_extents;
70 }
72 static long
73 decrease_reservation(
74 struct domain *d,
75 unsigned long *extent_list,
76 unsigned int nr_extents,
77 unsigned int extent_order,
78 unsigned int flags,
79 int *preempted)
80 {
81 struct pfn_info *page;
82 unsigned long i, j, mpfn;
84 if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
85 return 0;
87 for ( i = 0; i < nr_extents; i++ )
88 {
89 if ( hypercall_preempt_check() )
90 {
91 *preempted = 1;
92 return i;
93 }
95 if ( unlikely(__get_user(mpfn, &extent_list[i]) != 0) )
96 return i;
98 for ( j = 0; j < (1 << extent_order); j++ )
99 {
100 if ( unlikely((mpfn + j) >= max_page) )
101 {
102 DPRINTK("Domain %u page number out of range (%lx >= %lx)\n",
103 d->domain_id, mpfn + j, max_page);
104 return i;
105 }
107 page = pfn_to_page(mpfn + j);
108 if ( unlikely(!get_page(page, d)) )
109 {
110 DPRINTK("Bad page free for domain %u\n", d->domain_id);
111 return i;
112 }
114 if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
115 put_page_and_type(page);
117 if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
118 put_page(page);
120 shadow_sync_and_drop_references(d, page);
122 put_page(page);
123 }
124 }
126 return nr_extents;
127 }
129 /*
130 * To allow safe resume of do_memory_op() after preemption, we need to know
131 * at what point in the page list to resume. For this purpose I steal the
132 * high-order bits of the @cmd parameter, which are otherwise unused and zero.
133 */
134 #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
136 long do_memory_op(int cmd, void *arg)
137 {
138 struct domain *d;
139 int rc, start_extent, op, flags = 0, preempted = 0;
140 struct xen_memory_reservation reservation;
141 domid_t domid;
143 op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
145 switch ( op )
146 {
147 case XENMEM_increase_reservation:
148 case XENMEM_decrease_reservation:
149 if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
150 return -EFAULT;
152 start_extent = cmd >> START_EXTENT_SHIFT;
153 if ( unlikely(start_extent > reservation.nr_extents) )
154 return -EINVAL;
156 if ( reservation.extent_start != NULL )
157 reservation.extent_start += start_extent;
158 reservation.nr_extents -= start_extent;
160 if ( (reservation.address_bits != 0) &&
161 (reservation.address_bits <
162 (get_order_from_pages(max_page) + PAGE_SHIFT)) )
163 {
164 if ( reservation.address_bits < 31 )
165 return -ENOMEM;
166 flags = ALLOC_DOM_DMA;
167 }
169 if ( likely(reservation.domid == DOMID_SELF) )
170 d = current->domain;
171 else if ( !IS_PRIV(current->domain) )
172 return -EPERM;
173 else if ( (d = find_domain_by_id(reservation.domid)) == NULL )
174 return -ESRCH;
176 rc = ((op == XENMEM_increase_reservation) ?
177 increase_reservation : decrease_reservation)(
178 d,
179 reservation.extent_start,
180 reservation.nr_extents,
181 reservation.extent_order,
182 flags,
183 &preempted);
185 if ( unlikely(reservation.domid != DOMID_SELF) )
186 put_domain(d);
188 rc += start_extent;
190 if ( preempted )
191 return hypercall2_create_continuation(
192 __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg);
194 break;
196 case XENMEM_maximum_ram_page:
197 rc = max_page;
198 break;
200 case XENMEM_current_reservation:
201 case XENMEM_maximum_reservation:
202 if ( get_user(domid, (domid_t *)arg) )
203 return -EFAULT;
205 if ( likely((domid = (unsigned long)arg) == DOMID_SELF) )
206 d = current->domain;
207 else if ( !IS_PRIV(current->domain) )
208 return -EPERM;
209 else if ( (d = find_domain_by_id(domid)) == NULL )
210 return -ESRCH;
212 rc = (op == XENMEM_current_reservation) ? d->tot_pages : d->max_pages;
214 if ( unlikely(domid != DOMID_SELF) )
215 put_domain(d);
217 break;
219 default:
220 rc = arch_memory_op(op, arg);
221 break;
222 }
224 return rc;
225 }
227 /*
228 * Local variables:
229 * mode: C
230 * c-set-style: "BSD"
231 * c-basic-offset: 4
232 * tab-width: 4
233 * indent-tabs-mode: nil
234 * End:
235 */