ia64/xen-unstable

view xen/arch/x86/x86_64/compat/mm.c @ 18394:dade7f0bdc8d

hvm: Use main memory for video memory.

When creating an HVM domain, if e.g. another domain is created before
qemu allocates video memory, the extra 8MB memory ballooning is not
available any more, because it got consumed by the other domain.

This fixes it by taking video memory from the main memory:

- make hvmloader use e820_malloc to reserve some of the main memory
and notify ioemu of its address through the Xen platform PCI card.
- add XENMAPSPACE_mfn to the xen_add_to_physmap memory op, to allow
ioemu to move the MFNs between the original position and the PCI
mapping, when LFB acceleration is disabled/enabled
- add a remove_from_physmap memory op, to allow ioemu to unmap it
completely for the case of old guests with acceleration disabled.
- add xc_domain_memory_translate_gpfn_list to libxc to allow ioemu to
get the MFNs of the video memory.
- have xend save the PCI memory space instead of ioemu: if a memory
page is there, the guest can access it like usual memory, so xend
can safely be responsible to save it. The extra benefit is that
live migration will apply the logdirty optimization there too.
- handle old saved images, populating the video memory from ioemu if
really needed.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 14:53:39 2008 +0100 (2008-08-27)
parents ebbd0e8c3e72
children 4413d53a8320
line source
1 #ifdef CONFIG_COMPAT
3 #include <xen/event.h>
4 #include <xen/multicall.h>
5 #include <compat/memory.h>
6 #include <compat/xen.h>
8 int compat_set_gdt(XEN_GUEST_HANDLE(uint) frame_list, unsigned int entries)
9 {
10 unsigned int i, nr_pages = (entries + 511) / 512;
11 unsigned long frames[16];
12 long ret;
14 /* Rechecked in set_gdt, but ensures a sane limit for copy_from_user(). */
15 if ( entries > FIRST_RESERVED_GDT_ENTRY )
16 return -EINVAL;
18 if ( !guest_handle_okay(frame_list, nr_pages) )
19 return -EFAULT;
21 for ( i = 0; i < nr_pages; ++i )
22 {
23 unsigned int frame;
25 if ( __copy_from_guest(&frame, frame_list, 1) )
26 return -EFAULT;
27 frames[i] = frame;
28 guest_handle_add_offset(frame_list, 1);
29 }
31 domain_lock(current->domain);
33 if ( (ret = set_gdt(current, frames, entries)) == 0 )
34 flush_tlb_local();
36 domain_unlock(current->domain);
38 return ret;
39 }
41 int compat_update_descriptor(u32 pa_lo, u32 pa_hi, u32 desc_lo, u32 desc_hi)
42 {
43 return do_update_descriptor(pa_lo | ((u64)pa_hi << 32),
44 desc_lo | ((u64)desc_hi << 32));
45 }
47 int compat_arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
48 {
49 struct compat_machphys_mfn_list xmml;
50 l2_pgentry_t l2e;
51 unsigned long v;
52 compat_pfn_t mfn;
53 unsigned int i;
54 int rc = 0;
56 switch ( op )
57 {
58 case XENMEM_add_to_physmap:
59 {
60 struct compat_add_to_physmap cmp;
61 struct xen_add_to_physmap *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE;
63 if ( copy_from_guest(&cmp, arg, 1) )
64 return -EFAULT;
66 XLAT_add_to_physmap(nat, &cmp);
67 rc = arch_memory_op(op, guest_handle_from_ptr(nat, void));
69 break;
70 }
72 case XENMEM_remove_from_physmap:
73 {
74 struct compat_remove_from_physmap cmp;
75 struct xen_remove_from_physmap *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE;
77 if ( copy_from_guest(&cmp, arg, 1) )
78 return -EFAULT;
80 XLAT_remove_from_physmap(nat, &cmp);
81 rc = arch_memory_op(op, guest_handle_from_ptr(nat, void));
83 break;
84 }
86 case XENMEM_set_memory_map:
87 {
88 struct compat_foreign_memory_map cmp;
89 struct xen_foreign_memory_map *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE;
91 if ( copy_from_guest(&cmp, arg, 1) )
92 return -EFAULT;
94 #define XLAT_memory_map_HNDL_buffer(_d_, _s_) \
95 guest_from_compat_handle((_d_)->buffer, (_s_)->buffer)
96 XLAT_foreign_memory_map(nat, &cmp);
97 #undef XLAT_memory_map_HNDL_buffer
99 rc = arch_memory_op(op, guest_handle_from_ptr(nat, void));
101 break;
102 }
104 case XENMEM_memory_map:
105 case XENMEM_machine_memory_map:
106 {
107 struct compat_memory_map cmp;
108 struct xen_memory_map *nat = (void *)COMPAT_ARG_XLAT_VIRT_BASE;
110 if ( copy_from_guest(&cmp, arg, 1) )
111 return -EFAULT;
113 #define XLAT_memory_map_HNDL_buffer(_d_, _s_) \
114 guest_from_compat_handle((_d_)->buffer, (_s_)->buffer)
115 XLAT_memory_map(nat, &cmp);
116 #undef XLAT_memory_map_HNDL_buffer
118 rc = arch_memory_op(op, guest_handle_from_ptr(nat, void));
119 if ( rc < 0 )
120 break;
122 #define XLAT_memory_map_HNDL_buffer(_d_, _s_) ((void)0)
123 XLAT_memory_map(&cmp, nat);
124 #undef XLAT_memory_map_HNDL_buffer
125 if ( copy_to_guest(arg, &cmp, 1) )
126 rc = -EFAULT;
128 break;
129 }
131 case XENMEM_machphys_mapping:
132 {
133 struct domain *d = current->domain;
134 struct compat_machphys_mapping mapping = {
135 .v_start = MACH2PHYS_COMPAT_VIRT_START(d),
136 .v_end = MACH2PHYS_COMPAT_VIRT_END,
137 .max_mfn = MACH2PHYS_COMPAT_NR_ENTRIES(d) - 1
138 };
140 if ( copy_to_guest(arg, &mapping, 1) )
141 rc = -EFAULT;
143 break;
144 }
146 case XENMEM_machphys_mfn_list:
147 if ( copy_from_guest(&xmml, arg, 1) )
148 return -EFAULT;
150 for ( i = 0, v = RDWR_COMPAT_MPT_VIRT_START;
151 (i != xmml.max_extents) && (v != RDWR_COMPAT_MPT_VIRT_END);
152 i++, v += 1 << L2_PAGETABLE_SHIFT )
153 {
154 l2e = compat_idle_pg_table_l2[l2_table_offset(v)];
155 if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
156 break;
157 mfn = l2e_get_pfn(l2e) + l1_table_offset(v);
158 if ( copy_to_compat_offset(xmml.extent_start, i, &mfn, 1) )
159 return -EFAULT;
160 }
162 xmml.nr_extents = i;
163 if ( copy_to_guest(arg, &xmml, 1) )
164 rc = -EFAULT;
166 break;
168 default:
169 rc = -ENOSYS;
170 break;
171 }
173 return rc;
174 }
176 int compat_update_va_mapping(unsigned int va, u32 lo, u32 hi,
177 unsigned int flags)
178 {
179 return do_update_va_mapping(va, lo | ((u64)hi << 32), flags);
180 }
182 int compat_update_va_mapping_otherdomain(unsigned long va, u32 lo, u32 hi,
183 unsigned long flags,
184 domid_t domid)
185 {
186 return do_update_va_mapping_otherdomain(va, lo | ((u64)hi << 32), flags, domid);
187 }
189 DEFINE_XEN_GUEST_HANDLE(mmuext_op_compat_t);
191 int compat_mmuext_op(XEN_GUEST_HANDLE(mmuext_op_compat_t) cmp_uops,
192 unsigned int count,
193 XEN_GUEST_HANDLE(uint) pdone,
194 unsigned int foreigndom)
195 {
196 unsigned int i, preempt_mask;
197 int rc = 0;
198 XEN_GUEST_HANDLE(mmuext_op_t) nat_ops;
200 preempt_mask = count & MMU_UPDATE_PREEMPTED;
201 count ^= preempt_mask;
203 if ( unlikely(!guest_handle_okay(cmp_uops, count)) )
204 return -EFAULT;
206 set_xen_guest_handle(nat_ops, (void *)COMPAT_ARG_XLAT_VIRT_BASE);
208 for ( ; count; count -= i )
209 {
210 mmuext_op_t *nat_op = nat_ops.p;
211 unsigned int limit = COMPAT_ARG_XLAT_SIZE / sizeof(*nat_op);
212 int err;
214 for ( i = 0; i < min(limit, count); ++i )
215 {
216 mmuext_op_compat_t cmp_op;
217 enum XLAT_mmuext_op_arg1 arg1;
218 enum XLAT_mmuext_op_arg2 arg2;
220 if ( unlikely(__copy_from_guest(&cmp_op, cmp_uops, 1) != 0) )
221 {
222 rc = -EFAULT;
223 break;
224 }
226 switch ( cmp_op.cmd )
227 {
228 case MMUEXT_PIN_L1_TABLE:
229 case MMUEXT_PIN_L2_TABLE:
230 case MMUEXT_PIN_L3_TABLE:
231 case MMUEXT_PIN_L4_TABLE:
232 case MMUEXT_UNPIN_TABLE:
233 case MMUEXT_NEW_BASEPTR:
234 arg1 = XLAT_mmuext_op_arg1_mfn;
235 break;
236 default:
237 arg1 = XLAT_mmuext_op_arg1_linear_addr;
238 break;
239 case MMUEXT_NEW_USER_BASEPTR:
240 rc = -EINVAL;
241 case MMUEXT_TLB_FLUSH_LOCAL:
242 case MMUEXT_TLB_FLUSH_MULTI:
243 case MMUEXT_TLB_FLUSH_ALL:
244 case MMUEXT_FLUSH_CACHE:
245 arg1 = -1;
246 break;
247 }
249 if ( rc )
250 break;
252 switch ( cmp_op.cmd )
253 {
254 case MMUEXT_SET_LDT:
255 arg2 = XLAT_mmuext_op_arg2_nr_ents;
256 break;
257 case MMUEXT_TLB_FLUSH_MULTI:
258 case MMUEXT_INVLPG_MULTI:
259 arg2 = XLAT_mmuext_op_arg2_vcpumask;
260 break;
261 default:
262 arg2 = -1;
263 break;
264 }
266 #define XLAT_mmuext_op_HNDL_arg2_vcpumask(_d_, _s_) \
267 do \
268 { \
269 unsigned int vcpumask; \
270 if ( i < --limit ) \
271 { \
272 (_d_)->arg2.vcpumask.p = (void *)(nat_ops.p + limit); \
273 if ( copy_from_compat(&vcpumask, (_s_)->arg2.vcpumask, 1) == 0 ) \
274 *(unsigned long *)(_d_)->arg2.vcpumask.p = vcpumask; \
275 else \
276 rc = -EFAULT; \
277 } \
278 } while(0)
279 XLAT_mmuext_op(nat_op, &cmp_op);
280 #undef XLAT_mmuext_op_HNDL_arg2_vcpumask
282 if ( rc || i >= limit )
283 break;
285 guest_handle_add_offset(cmp_uops, 1);
286 ++nat_op;
287 }
289 err = do_mmuext_op(nat_ops, i | preempt_mask, pdone, foreigndom);
291 if ( err )
292 {
293 BUILD_BUG_ON(__HYPERVISOR_mmuext_op <= 0);
294 if ( err == __HYPERVISOR_mmuext_op )
295 {
296 struct cpu_user_regs *regs = guest_cpu_user_regs();
297 struct mc_state *mcs = &this_cpu(mc_state);
298 unsigned int arg1 = !test_bit(_MCSF_in_multicall, &mcs->flags)
299 ? regs->ecx
300 : mcs->call.args[1];
301 unsigned int left = arg1 & ~MMU_UPDATE_PREEMPTED;
303 BUG_ON(left == arg1);
304 BUG_ON(left > count);
305 guest_handle_add_offset(nat_ops, i - left);
306 guest_handle_subtract_offset(cmp_uops, left);
307 left = 1;
308 BUG_ON(!hypercall_xlat_continuation(&left, 0x01, nat_ops, cmp_uops));
309 BUG_ON(left != arg1);
310 if (!test_bit(_MCSF_in_multicall, &mcs->flags))
311 regs->_ecx += count - i;
312 else
313 mcs->compat_call.args[1] += count - i;
314 }
315 else
316 BUG_ON(err > 0);
317 rc = err;
318 }
320 if ( rc )
321 break;
323 /* Force do_mmuext_op() to not start counting from zero again. */
324 preempt_mask = MMU_UPDATE_PREEMPTED;
325 }
327 return rc;
328 }
330 #endif /* CONFIG_COMPAT */
332 /*
333 * Local variables:
334 * mode: C
335 * c-set-style: "BSD"
336 * c-basic-offset: 4
337 * tab-width: 4
338 * indent-tabs-mode: nil
339 * End:
340 */