source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/domctl.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 13.2 KB
Line 
1/******************************************************************************
2 * Arch-specific domctl.c
3 *
4 * Copyright (c) 2002-2006, K A Fraser
5 */
6
7#include <xen/config.h>
8#include <xen/types.h>
9#include <xen/lib.h>
10#include <xen/mm.h>
11#include <xen/guest_access.h>
12#include <xen/compat.h>
13#include <public/domctl.h>
14#include <xen/sched.h>
15#include <xen/domain.h>
16#include <xen/event.h>
17#include <xen/domain_page.h>
18#include <asm/msr.h>
19#include <xen/trace.h>
20#include <xen/console.h>
21#include <xen/iocap.h>
22#include <asm/paging.h>
23#include <asm/irq.h>
24#include <asm/hvm/hvm.h>
25#include <asm/hvm/support.h>
26#include <asm/processor.h>
27#include <public/hvm/e820.h>
28
29long arch_do_domctl(
30    struct xen_domctl *domctl,
31    XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
32{
33    long ret = 0;
34
35    switch ( domctl->cmd )
36    {
37
38    case XEN_DOMCTL_shadow_op:
39    {
40        struct domain *d;
41        ret = -ESRCH;
42        d = rcu_lock_domain_by_id(domctl->domain);
43        if ( d != NULL )
44        {
45            ret = paging_domctl(d,
46                                &domctl->u.shadow_op,
47                                guest_handle_cast(u_domctl, void));
48            rcu_unlock_domain(d);
49            copy_to_guest(u_domctl, domctl, 1);
50        } 
51    }
52    break;
53
54    case XEN_DOMCTL_ioport_permission:
55    {
56        struct domain *d;
57        unsigned int fp = domctl->u.ioport_permission.first_port;
58        unsigned int np = domctl->u.ioport_permission.nr_ports;
59
60        ret = -EINVAL;
61        if ( (fp + np) > 65536 )
62            break;
63
64        ret = -ESRCH;
65        if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) )
66            break;
67
68        if ( np == 0 )
69            ret = 0;
70        else if ( domctl->u.ioport_permission.allow_access )
71            ret = ioports_permit_access(d, fp, fp + np - 1);
72        else
73            ret = ioports_deny_access(d, fp, fp + np - 1);
74
75        rcu_unlock_domain(d);
76    }
77    break;
78
79    case XEN_DOMCTL_getpageframeinfo:
80    {
81        struct page_info *page;
82        unsigned long mfn = domctl->u.getpageframeinfo.gmfn;
83        domid_t dom = domctl->domain;
84        struct domain *d;
85
86        ret = -EINVAL;
87
88        if ( unlikely(!mfn_valid(mfn)) ||
89             unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
90            break;
91
92        page = mfn_to_page(mfn);
93
94        if ( likely(get_page(page, d)) )
95        {
96            ret = 0;
97
98            domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_NOTAB;
99
100            if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
101            {
102                switch ( page->u.inuse.type_info & PGT_type_mask )
103                {
104                case PGT_l1_page_table:
105                    domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L1TAB;
106                    break;
107                case PGT_l2_page_table:
108                    domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L2TAB;
109                    break;
110                case PGT_l3_page_table:
111                    domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L3TAB;
112                    break;
113                case PGT_l4_page_table:
114                    domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L4TAB;
115                    break;
116                }
117            }
118           
119            put_page(page);
120        }
121
122        rcu_unlock_domain(d);
123
124        copy_to_guest(u_domctl, domctl, 1);
125    }
126    break;
127
128    case XEN_DOMCTL_getpageframeinfo2:
129    {
130        int n,j;
131        int num = domctl->u.getpageframeinfo2.num;
132        domid_t dom = domctl->domain;
133        struct domain *d;
134        uint32_t *arr32;
135        ret = -ESRCH;
136
137        if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
138            break;
139
140        if ( unlikely(num > 1024) )
141        {
142            ret = -E2BIG;
143            rcu_unlock_domain(d);
144            break;
145        }
146
147        arr32 = alloc_xenheap_page();
148        if ( !arr32 )
149        {
150            ret = -ENOMEM;
151            put_domain(d);
152            break;
153        }
154 
155        ret = 0;
156        for ( n = 0; n < num; )
157        {
158            int k = PAGE_SIZE / 4;
159            if ( (num - n) < k )
160                k = num - n;
161
162            if ( copy_from_guest_offset(arr32,
163                                        domctl->u.getpageframeinfo2.array,
164                                        n, k) )
165            {
166                ret = -EFAULT;
167                break;
168            }
169     
170            for ( j = 0; j < k; j++ )
171            {     
172                struct page_info *page;
173                unsigned long mfn = arr32[j];
174
175                page = mfn_to_page(mfn);
176
177                if ( likely(mfn_valid(mfn) && get_page(page, d)) ) 
178                {
179                    unsigned long type = 0;
180
181                    switch( page->u.inuse.type_info & PGT_type_mask )
182                    {
183                    case PGT_l1_page_table:
184                        type = XEN_DOMCTL_PFINFO_L1TAB;
185                        break;
186                    case PGT_l2_page_table:
187                        type = XEN_DOMCTL_PFINFO_L2TAB;
188                        break;
189                    case PGT_l3_page_table:
190                        type = XEN_DOMCTL_PFINFO_L3TAB;
191                        break;
192                    case PGT_l4_page_table:
193                        type = XEN_DOMCTL_PFINFO_L4TAB;
194                        break;
195                    }
196
197                    if ( page->u.inuse.type_info & PGT_pinned )
198                        type |= XEN_DOMCTL_PFINFO_LPINTAB;
199                    arr32[j] |= type;
200                    put_page(page);
201                }
202                else
203                    arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
204
205            }
206
207            if ( copy_to_guest_offset(domctl->u.getpageframeinfo2.array,
208                                      n, arr32, k) )
209            {
210                ret = -EFAULT;
211                break;
212            }
213
214            n += k;
215        }
216
217        free_xenheap_page(arr32);
218
219        rcu_unlock_domain(d);
220    }
221    break;
222
223    case XEN_DOMCTL_getmemlist:
224    {
225        int i;
226        struct domain *d = rcu_lock_domain_by_id(domctl->domain);
227        unsigned long max_pfns = domctl->u.getmemlist.max_pfns;
228        uint64_t mfn;
229        struct list_head *list_ent;
230
231        ret = -EINVAL;
232        if ( d != NULL )
233        {
234            ret = 0;
235
236            spin_lock(&d->page_alloc_lock);
237
238            list_ent = d->page_list.next;
239            for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
240            {
241                mfn = page_to_mfn(list_entry(
242                    list_ent, struct page_info, list));
243                if ( copy_to_guest_offset(domctl->u.getmemlist.buffer,
244                                          i, &mfn, 1) )
245                {
246                    ret = -EFAULT;
247                    break;
248                }
249                list_ent = mfn_to_page(mfn)->list.next;
250            }
251           
252            spin_unlock(&d->page_alloc_lock);
253
254            domctl->u.getmemlist.num_pfns = i;
255            copy_to_guest(u_domctl, domctl, 1);
256
257            rcu_unlock_domain(d);
258        }
259    }
260    break;
261
262    case XEN_DOMCTL_hypercall_init:
263    {
264        struct domain *d = rcu_lock_domain_by_id(domctl->domain);
265        unsigned long gmfn = domctl->u.hypercall_init.gmfn;
266        unsigned long mfn;
267        void *hypercall_page;
268
269        ret = -ESRCH;
270        if ( unlikely(d == NULL) )
271            break;
272
273        mfn = gmfn_to_mfn(d, gmfn);
274
275        ret = -EACCES;
276        if ( !mfn_valid(mfn) ||
277             !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
278        {
279            rcu_unlock_domain(d);
280            break;
281        }
282
283        ret = 0;
284
285        hypercall_page = map_domain_page(mfn);
286        hypercall_page_initialise(d, hypercall_page);
287        unmap_domain_page(hypercall_page);
288
289        put_page_and_type(mfn_to_page(mfn));
290
291        rcu_unlock_domain(d);
292    }
293    break;
294
295    case XEN_DOMCTL_sethvmcontext:
296    { 
297        struct hvm_domain_context c;
298        struct domain             *d;
299
300        c.cur = 0;
301        c.size = domctl->u.hvmcontext.size;
302        c.data = NULL;
303       
304        ret = -ESRCH;
305        if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
306            break;
307
308        ret = -EINVAL;
309        if ( !is_hvm_domain(d) ) 
310            goto sethvmcontext_out;
311
312        ret = -ENOMEM;
313        if ( (c.data = xmalloc_bytes(c.size)) == NULL )
314            goto sethvmcontext_out;
315
316        ret = -EFAULT;
317        if ( copy_from_guest(c.data, domctl->u.hvmcontext.buffer, c.size) != 0)
318            goto sethvmcontext_out;
319
320        ret = hvm_load(d, &c);
321
322    sethvmcontext_out:
323        if ( c.data != NULL )
324            xfree(c.data);
325
326        rcu_unlock_domain(d);
327    }
328    break;
329
330    case XEN_DOMCTL_gethvmcontext:
331    { 
332        struct hvm_domain_context c;
333        struct domain             *d;
334
335        ret = -ESRCH;
336        if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
337            break;
338
339        ret = -EINVAL;
340        if ( !is_hvm_domain(d) ) 
341            goto gethvmcontext_out;
342
343        c.cur = 0;
344        c.size = hvm_save_size(d);
345        c.data = NULL;
346
347        if ( guest_handle_is_null(domctl->u.hvmcontext.buffer) )
348        {
349            /* Client is querying for the correct buffer size */
350            domctl->u.hvmcontext.size = c.size;
351            ret = 0;
352            goto gethvmcontext_out;           
353        }
354
355        /* Check that the client has a big enough buffer */
356        ret = -ENOSPC;
357        if ( domctl->u.hvmcontext.size < c.size ) 
358            goto gethvmcontext_out;
359
360        /* Allocate our own marshalling buffer */
361        ret = -ENOMEM;
362        if ( (c.data = xmalloc_bytes(c.size)) == NULL )
363            goto gethvmcontext_out;
364
365        ret = hvm_save(d, &c);
366
367        domctl->u.hvmcontext.size = c.cur;
368        if ( copy_to_guest(domctl->u.hvmcontext.buffer, c.data, c.size) != 0 )
369            ret = -EFAULT;
370
371    gethvmcontext_out:
372        if ( copy_to_guest(u_domctl, domctl, 1) )
373            ret = -EFAULT;
374
375        if ( c.data != NULL )
376            xfree(c.data);
377
378        rcu_unlock_domain(d);
379    }
380    break;
381
382    case XEN_DOMCTL_set_address_size:
383    {
384        struct domain *d;
385
386        ret = -ESRCH;
387        if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
388            break;
389
390        switch ( domctl->u.address_size.size )
391        {
392#ifdef CONFIG_COMPAT
393        case 32:
394            ret = switch_compat(d);
395            break;
396        case 64:
397            ret = switch_native(d);
398            break;
399#endif
400        default:
401            ret = (domctl->u.address_size.size == BITS_PER_LONG) ? 0 : -EINVAL;
402            break;
403        }
404
405        rcu_unlock_domain(d);
406    }
407    break;
408
409    case XEN_DOMCTL_get_address_size:
410    {
411        struct domain *d;
412
413        ret = -ESRCH;
414        if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
415            break;
416
417        domctl->u.address_size.size = BITS_PER_GUEST_LONG(d);
418
419        ret = 0;
420        rcu_unlock_domain(d);
421
422        if ( copy_to_guest(u_domctl, domctl, 1) )
423            ret = -EFAULT;
424    }
425    break;
426
427    default:
428        ret = -ENOSYS;
429        break;
430    }
431
432    return ret;
433}
434
435void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
436{
437#ifdef CONFIG_COMPAT
438#define c(fld) (!is_pv_32on64_domain(v->domain) ? (c.nat->fld) : (c.cmp->fld))
439#else
440#define c(fld) (c.nat->fld)
441#endif
442
443    if ( !is_pv_32on64_domain(v->domain) )
444        memcpy(c.nat, &v->arch.guest_context, sizeof(*c.nat));
445#ifdef CONFIG_COMPAT
446    else
447        XLAT_vcpu_guest_context(c.cmp, &v->arch.guest_context);
448#endif
449
450    c(flags &= ~(VGCF_i387_valid|VGCF_in_kernel));
451    if ( v->fpu_initialised )
452        c(flags |= VGCF_i387_valid);
453    if ( !test_bit(_VPF_down, &v->pause_flags) )
454        c(flags |= VGCF_online);
455
456    if ( is_hvm_vcpu(v) )
457    {
458        if ( !is_pv_32on64_domain(v->domain) )
459            hvm_store_cpu_guest_regs(v, &c.nat->user_regs, c.nat->ctrlreg);
460#ifdef CONFIG_COMPAT
461        else
462        {
463            struct cpu_user_regs user_regs;
464            typeof(c.nat->ctrlreg) ctrlreg;
465            unsigned i;
466
467            hvm_store_cpu_guest_regs(v, &user_regs, ctrlreg);
468            XLAT_cpu_user_regs(&c.cmp->user_regs, &user_regs);
469            for ( i = 0; i < ARRAY_SIZE(c.cmp->ctrlreg); ++i )
470                c.cmp->ctrlreg[i] = ctrlreg[i];
471        }
472#endif
473    }
474    else
475    {
476        /* IOPL privileges are virtualised: merge back into returned eflags. */
477        BUG_ON((c(user_regs.eflags) & EF_IOPL) != 0);
478        c(user_regs.eflags |= v->arch.iopl << 12);
479
480        if ( !is_pv_32on64_domain(v->domain) )
481        {
482            c.nat->ctrlreg[3] = xen_pfn_to_cr3(
483                pagetable_get_pfn(v->arch.guest_table));
484#ifdef __x86_64__
485            if ( !pagetable_is_null(v->arch.guest_table_user) )
486                c.nat->ctrlreg[1] = xen_pfn_to_cr3(
487                    pagetable_get_pfn(v->arch.guest_table_user));
488#endif
489        }
490#ifdef CONFIG_COMPAT
491        else
492        {
493            l4_pgentry_t *l4e = __va(pagetable_get_paddr(v->arch.guest_table));
494            c.cmp->ctrlreg[3] = compat_pfn_to_cr3(l4e_get_pfn(*l4e));
495        }
496#endif
497
498        if ( guest_kernel_mode(v, &v->arch.guest_context.user_regs) )
499            c(flags |= VGCF_in_kernel);
500    }
501
502    c(vm_assist = v->domain->vm_assist);
503#undef c
504}
505
506/*
507 * Local variables:
508 * mode: C
509 * c-set-style: "BSD"
510 * c-basic-offset: 4
511 * tab-width: 4
512 * indent-tabs-mode: nil
513 * End:
514 */
Note: See TracBrowser for help on using the repository browser.