1 /*
2  * Copyright (C) 2005 Hewlett-Packard Co.
3  * written by Aravind Menon & Jose Renato Santos
4  *            (email: xenoprof@groups.hp.com)
5  *
6  * arch generic xenoprof and IA64 support.
7  * dynamic map/unmap xenoprof buffer support.
8  * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
9  *                    VA Linux Systems Japan K.K.
10  */
11 
12 #ifndef COMPAT
13 #include <xen/guest_access.h>
14 #include <xen/sched.h>
15 #include <xen/event.h>
16 #include <xen/xenoprof.h>
17 #include <public/xenoprof.h>
18 #include <xen/paging.h>
19 #include <xsm/xsm.h>
20 #include <xen/hypercall.h>
21 
22 /* Override macros from asm/page.h to make them work with mfn_t */
23 #undef virt_to_mfn
24 #define virt_to_mfn(va) _mfn(__virt_to_mfn(va))
25 
26 #define XENOPROF_DOMAIN_IGNORED    0
27 #define XENOPROF_DOMAIN_ACTIVE     1
28 #define XENOPROF_DOMAIN_PASSIVE    2
29 
30 #define XENOPROF_IDLE              0
31 #define XENOPROF_INITIALIZED       1
32 #define XENOPROF_COUNTERS_RESERVED 2
33 #define XENOPROF_READY             3
34 #define XENOPROF_PROFILING         4
35 
36 #ifndef CONFIG_COMPAT
37 #define XENOPROF_COMPAT(x) false
38 typedef struct xenoprof_buf xenoprof_buf_t;
39 #define xenoprof_buf(d, b, field) ACCESS_ONCE((b)->field)
40 #else
41 #include <compat/xenoprof.h>
42 #define XENOPROF_COMPAT(x) ((x)->is_compat)
43 typedef union {
44     struct xenoprof_buf native;
45     struct compat_oprof_buf compat;
46 } xenoprof_buf_t;
47 #define xenoprof_buf(d, b, field) ACCESS_ONCE(*(!(d)->xenoprof->is_compat \
48                                                 ? &(b)->native.field \
49                                                 : &(b)->compat.field))
50 #endif
51 
52 /* Limit amount of pages used for shared buffer (per domain) */
53 #define MAX_OPROF_SHARED_PAGES 32
54 
55 /* Lock protecting the following global state */
56 static DEFINE_SPINLOCK(xenoprof_lock);
57 
58 static DEFINE_SPINLOCK(pmu_owner_lock);
59 int pmu_owner = 0;
60 int pmu_hvm_refcount = 0;
61 
62 struct xenoprof_vcpu {
63     int event_size;
64     xenoprof_buf_t *buffer;
65 };
66 
67 struct xenoprof {
68     char *rawbuf;
69     int npages;
70     int nbuf;
71     int bufsize;
72     int domain_type;
73 #ifdef CONFIG_COMPAT
74     bool is_compat;
75 #endif
76     struct xenoprof_vcpu *vcpu;
77 };
78 
79 static struct domain *active_domains[MAX_OPROF_DOMAINS];
80 static int active_ready[MAX_OPROF_DOMAINS];
81 static unsigned int adomains;
82 
83 static struct domain *passive_domains[MAX_OPROF_DOMAINS];
84 static unsigned int pdomains;
85 
86 static unsigned int activated;
87 static struct domain *xenoprof_primary_profiler;
88 static int xenoprof_state = XENOPROF_IDLE;
89 static unsigned long backtrace_depth;
90 
91 static u64 total_samples;
92 static u64 invalid_buffer_samples;
93 static u64 corrupted_buffer_samples;
94 static u64 lost_samples;
95 static u64 active_samples;
96 static u64 passive_samples;
97 static u64 idle_samples;
98 static u64 others_samples;
99 
acquire_pmu_ownership(int pmu_ownership)100 int acquire_pmu_ownership(int pmu_ownership)
101 {
102     spin_lock(&pmu_owner_lock);
103     if ( pmu_owner == PMU_OWNER_NONE )
104     {
105         pmu_owner = pmu_ownership;
106         goto out;
107     }
108 
109     if ( pmu_owner == pmu_ownership )
110         goto out;
111 
112     spin_unlock(&pmu_owner_lock);
113     return 0;
114  out:
115     if ( pmu_owner == PMU_OWNER_HVM )
116         pmu_hvm_refcount++;
117     spin_unlock(&pmu_owner_lock);
118     return 1;
119 }
120 
release_pmu_ownership(int pmu_ownership)121 void release_pmu_ownership(int pmu_ownership)
122 {
123     spin_lock(&pmu_owner_lock);
124     if ( pmu_ownership == PMU_OWNER_HVM )
125         pmu_hvm_refcount--;
126     if ( !pmu_hvm_refcount )
127         pmu_owner = PMU_OWNER_NONE;
128     spin_unlock(&pmu_owner_lock);
129 }
130 
is_active(struct domain * d)131 int is_active(struct domain *d)
132 {
133     struct xenoprof *x = d->xenoprof;
134     return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE));
135 }
136 
is_passive(struct domain * d)137 int is_passive(struct domain *d)
138 {
139     struct xenoprof *x = d->xenoprof;
140     return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE));
141 }
142 
is_profiled(struct domain * d)143 static int is_profiled(struct domain *d)
144 {
145     return (is_active(d) || is_passive(d));
146 }
147 
xenoprof_reset_stat(void)148 static void xenoprof_reset_stat(void)
149 {
150     total_samples = 0;
151     invalid_buffer_samples = 0;
152     corrupted_buffer_samples = 0;
153     lost_samples = 0;
154     active_samples = 0;
155     passive_samples = 0;
156     idle_samples = 0;
157     others_samples = 0;
158 }
159 
xenoprof_reset_buf(struct domain * d)160 static void xenoprof_reset_buf(struct domain *d)
161 {
162     int j;
163     xenoprof_buf_t *buf;
164 
165     if ( d->xenoprof == NULL )
166     {
167         printk("xenoprof_reset_buf: ERROR - Unexpected "
168                "Xenoprof NULL pointer \n");
169         return;
170     }
171 
172     for ( j = 0; j < d->max_vcpus; j++ )
173     {
174         buf = d->xenoprof->vcpu[j].buffer;
175         if ( buf != NULL )
176         {
177             xenoprof_buf(d, buf, event_head) = 0;
178             xenoprof_buf(d, buf, event_tail) = 0;
179         }
180     }
181 }
182 
183 static int
share_xenoprof_page_with_guest(struct domain * d,mfn_t mfn,int npages)184 share_xenoprof_page_with_guest(struct domain *d, mfn_t mfn, int npages)
185 {
186     int i;
187 
188     /* Check if previous page owner has released the page. */
189     for ( i = 0; i < npages; i++ )
190     {
191         struct page_info *page = mfn_to_page(mfn_add(mfn, i));
192 
193         if ( (page->count_info & (PGC_allocated|PGC_count_mask)) != 0 )
194         {
195             printk(XENLOG_G_INFO "dom%d mfn %#lx page->count_info %#lx\n",
196                    d->domain_id, mfn_x(mfn_add(mfn, i)), page->count_info);
197             return -EBUSY;
198         }
199         page_set_owner(page, NULL);
200     }
201 
202     for ( i = 0; i < npages; i++ )
203         share_xen_page_with_guest(mfn_to_page(mfn_add(mfn, i)), d, SHARE_rw);
204 
205     return 0;
206 }
207 
208 static void
unshare_xenoprof_page_with_guest(struct xenoprof * x)209 unshare_xenoprof_page_with_guest(struct xenoprof *x)
210 {
211     int i, npages = x->npages;
212     mfn_t mfn = virt_to_mfn(x->rawbuf);
213 
214     for ( i = 0; i < npages; i++ )
215     {
216         struct page_info *page = mfn_to_page(mfn_add(mfn, i));
217 
218         BUG_ON(page_get_owner(page) != current->domain);
219         put_page_alloc_ref(page);
220     }
221 }
222 
223 static void
xenoprof_shared_gmfn_with_guest(struct domain * d,unsigned long maddr,unsigned long gmaddr,int npages)224 xenoprof_shared_gmfn_with_guest(
225     struct domain *d, unsigned long maddr, unsigned long gmaddr, int npages)
226 {
227     int i;
228 
229     for ( i = 0; i < npages; i++, maddr += PAGE_SIZE, gmaddr += PAGE_SIZE )
230     {
231         BUG_ON(page_get_owner(maddr_to_page(maddr)) != d);
232         if ( i == 0 )
233             gdprintk(XENLOG_WARNING,
234                      "xenoprof unsupported with autotranslated guests\n");
235 
236     }
237 }
238 
alloc_xenoprof_struct(struct domain * d,int max_samples,int is_passive)239 static int alloc_xenoprof_struct(
240     struct domain *d, int max_samples, int is_passive)
241 {
242     struct vcpu *v;
243     int nvcpu, npages, bufsize, max_bufsize;
244     unsigned max_max_samples;
245     int i;
246 
247     nvcpu = 0;
248     for_each_vcpu ( d, v )
249         nvcpu++;
250 
251     if ( !nvcpu )
252         return -EINVAL;
253 
254     d->xenoprof = xzalloc(struct xenoprof);
255     if ( d->xenoprof == NULL )
256     {
257         printk("alloc_xenoprof_struct(): memory allocation failed\n");
258         return -ENOMEM;
259     }
260 
261     d->xenoprof->vcpu = xzalloc_array(struct xenoprof_vcpu, d->max_vcpus);
262     if ( d->xenoprof->vcpu == NULL )
263     {
264         xfree(d->xenoprof);
265         d->xenoprof = NULL;
266         printk("alloc_xenoprof_struct(): vcpu array allocation failed\n");
267         return -ENOMEM;
268     }
269 
270     bufsize = sizeof(struct xenoprof_buf);
271     i = sizeof(struct event_log);
272 #ifdef CONFIG_COMPAT
273     d->xenoprof->is_compat = is_pv_32bit_domain(is_passive ? hardware_domain : d);
274     if ( XENOPROF_COMPAT(d->xenoprof) )
275     {
276         bufsize = sizeof(struct compat_oprof_buf);
277         i = sizeof(struct compat_event_log);
278     }
279 #endif
280 
281     /* reduce max_samples if necessary to limit pages allocated */
282     max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu;
283     max_max_samples = ( (max_bufsize - bufsize) / i ) + 1;
284     if ( (unsigned)max_samples > max_max_samples )
285         max_samples = max_max_samples;
286 
287     bufsize += (max_samples - 1) * i;
288     npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1;
289 
290     d->xenoprof->rawbuf = alloc_xenheap_pages(get_order_from_pages(npages), 0);
291     if ( d->xenoprof->rawbuf == NULL )
292     {
293         xfree(d->xenoprof->vcpu);
294         xfree(d->xenoprof);
295         d->xenoprof = NULL;
296         return -ENOMEM;
297     }
298 
299     for ( i = 0; i < npages; ++i )
300         clear_page(d->xenoprof->rawbuf + i * PAGE_SIZE);
301 
302     d->xenoprof->npages = npages;
303     d->xenoprof->nbuf = nvcpu;
304     d->xenoprof->bufsize = bufsize;
305     d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
306 
307     /* Update buffer pointers for active vcpus */
308     i = 0;
309     for_each_vcpu ( d, v )
310     {
311         xenoprof_buf_t *buf = (xenoprof_buf_t *)
312             &d->xenoprof->rawbuf[i * bufsize];
313 
314         d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples;
315         d->xenoprof->vcpu[v->vcpu_id].buffer = buf;
316         xenoprof_buf(d, buf, event_size) = max_samples;
317         xenoprof_buf(d, buf, vcpu_id) = v->vcpu_id;
318 
319         i++;
320         /* in the unlikely case that the number of active vcpus changes */
321         if ( i >= nvcpu )
322             break;
323     }
324 
325     return 0;
326 }
327 
free_xenoprof_pages(struct domain * d)328 void free_xenoprof_pages(struct domain *d)
329 {
330     struct xenoprof *x;
331     int order;
332 
333     x = d->xenoprof;
334     if ( x == NULL )
335         return;
336 
337     if ( x->rawbuf != NULL )
338     {
339         order = get_order_from_pages(x->npages);
340         free_xenheap_pages(x->rawbuf, order);
341     }
342 
343     xfree(x->vcpu);
344     xfree(x);
345     d->xenoprof = NULL;
346 }
347 
active_index(struct domain * d)348 static int active_index(struct domain *d)
349 {
350     int i;
351 
352     for ( i = 0; i < adomains; i++ )
353         if ( active_domains[i] == d )
354             return i;
355 
356     return -1;
357 }
358 
set_active(struct domain * d)359 static int set_active(struct domain *d)
360 {
361     int ind;
362     struct xenoprof *x;
363 
364     ind = active_index(d);
365     if ( ind < 0 )
366         return -EPERM;
367 
368     x = d->xenoprof;
369     if ( x == NULL )
370         return -EPERM;
371 
372     x->domain_type = XENOPROF_DOMAIN_ACTIVE;
373     active_ready[ind] = 1;
374     activated++;
375 
376     return 0;
377 }
378 
reset_active(struct domain * d)379 static int reset_active(struct domain *d)
380 {
381     int ind;
382     struct xenoprof *x;
383 
384     ind = active_index(d);
385     if ( ind < 0 )
386         return -EPERM;
387 
388     x = d->xenoprof;
389     if ( x == NULL )
390         return -EPERM;
391 
392     x->domain_type = XENOPROF_DOMAIN_IGNORED;
393     active_ready[ind] = 0;
394     active_domains[ind] = NULL;
395     activated--;
396     put_domain(d);
397 
398     if ( activated <= 0 )
399         adomains = 0;
400 
401     return 0;
402 }
403 
reset_passive(struct domain * d)404 static void reset_passive(struct domain *d)
405 {
406     struct xenoprof *x;
407 
408     if ( d == NULL )
409         return;
410 
411     x = d->xenoprof;
412     if ( x == NULL )
413         return;
414 
415     x->domain_type = XENOPROF_DOMAIN_IGNORED;
416     unshare_xenoprof_page_with_guest(x);
417 }
418 
reset_active_list(void)419 static void reset_active_list(void)
420 {
421     int i;
422 
423     for ( i = 0; i < adomains; i++ )
424         if ( active_ready[i] )
425             reset_active(active_domains[i]);
426 
427     adomains = 0;
428     activated = 0;
429 }
430 
reset_passive_list(void)431 static void reset_passive_list(void)
432 {
433     int i;
434 
435     for ( i = 0; i < pdomains; i++ )
436     {
437         reset_passive(passive_domains[i]);
438         put_domain(passive_domains[i]);
439         passive_domains[i] = NULL;
440     }
441 
442     pdomains = 0;
443 }
444 
add_active_list(domid_t domid)445 static int add_active_list(domid_t domid)
446 {
447     struct domain *d;
448 
449     if ( adomains >= MAX_OPROF_DOMAINS )
450         return -E2BIG;
451 
452     d = get_domain_by_id(domid);
453     if ( d == NULL )
454         return -EINVAL;
455 
456     active_domains[adomains] = d;
457     active_ready[adomains] = 0;
458     adomains++;
459 
460     return 0;
461 }
462 
add_passive_list(XEN_GUEST_HANDLE_PARAM (void)arg)463 static int add_passive_list(XEN_GUEST_HANDLE_PARAM(void) arg)
464 {
465     struct xenoprof_passive passive;
466     struct domain *d;
467     int ret = 0;
468 
469     if ( pdomains >= MAX_OPROF_DOMAINS )
470         return -E2BIG;
471 
472     if ( copy_from_guest(&passive, arg, 1) )
473         return -EFAULT;
474 
475     d = get_domain_by_id(passive.domain_id);
476     if ( d == NULL )
477         return -EINVAL;
478 
479     if ( d->xenoprof == NULL )
480     {
481         ret = alloc_xenoprof_struct(d, passive.max_samples, 1);
482         if ( ret < 0 )
483         {
484             put_domain(d);
485             return -ENOMEM;
486         }
487     }
488 
489     ret = share_xenoprof_page_with_guest(
490         current->domain, virt_to_mfn(d->xenoprof->rawbuf),
491         d->xenoprof->npages);
492     if ( ret < 0 )
493     {
494         put_domain(d);
495         return ret;
496     }
497 
498     d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE;
499     passive.nbuf = d->xenoprof->nbuf;
500     passive.bufsize = d->xenoprof->bufsize;
501     if ( !paging_mode_translate(current->domain) )
502         passive.buf_gmaddr = __pa(d->xenoprof->rawbuf);
503     else
504         xenoprof_shared_gmfn_with_guest(
505             current->domain, __pa(d->xenoprof->rawbuf),
506             passive.buf_gmaddr, d->xenoprof->npages);
507 
508     if ( __copy_to_guest(arg, &passive, 1) )
509     {
510         put_domain(d);
511         return -EFAULT;
512     }
513 
514     passive_domains[pdomains] = d;
515     pdomains++;
516 
517     return ret;
518 }
519 
520 
521 /* Get space in the buffer */
xenoprof_buf_space(int head,int tail,int size)522 static int xenoprof_buf_space(int head, int tail, int size)
523 {
524     return ((tail > head) ? 0 : size) + tail - head - 1;
525 }
526 
527 /* Check for space and add a sample. Return 1 if successful, 0 otherwise. */
xenoprof_add_sample(const struct domain * d,const struct xenoprof_vcpu * v,uint64_t eip,int mode,int event)528 static int xenoprof_add_sample(const struct domain *d,
529                                const struct xenoprof_vcpu *v,
530                                uint64_t eip, int mode, int event)
531 {
532     xenoprof_buf_t *buf = v->buffer;
533     int head, tail, size;
534 
535     head = xenoprof_buf(d, buf, event_head);
536     tail = xenoprof_buf(d, buf, event_tail);
537     size = v->event_size;
538 
539     /* make sure indexes in shared buffer are sane */
540     if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
541     {
542         corrupted_buffer_samples++;
543         return 0;
544     }
545 
546     if ( xenoprof_buf_space(head, tail, size) > 0 )
547     {
548         xenoprof_buf(d, buf, event_log[head].eip) = eip;
549         xenoprof_buf(d, buf, event_log[head].mode) = mode;
550         xenoprof_buf(d, buf, event_log[head].event) = event;
551         head++;
552         if ( head >= size )
553             head = 0;
554 
555         xenoprof_buf(d, buf, event_head) = head;
556     }
557     else
558     {
559         xenoprof_buf(d, buf, lost_samples)++;
560         lost_samples++;
561         return 0;
562     }
563 
564     return 1;
565 }
566 
xenoprof_add_trace(struct vcpu * vcpu,uint64_t pc,int mode)567 int xenoprof_add_trace(struct vcpu *vcpu, uint64_t pc, int mode)
568 {
569     struct domain *d = vcpu->domain;
570 
571     /* Do not accidentally write an escape code due to a broken frame. */
572     if ( pc == XENOPROF_ESCAPE_CODE )
573     {
574         invalid_buffer_samples++;
575         return 0;
576     }
577 
578     return xenoprof_add_sample(d, &d->xenoprof->vcpu[vcpu->vcpu_id],
579                                pc, mode, 0);
580 }
581 
xenoprof_log_event(struct vcpu * vcpu,const struct cpu_user_regs * regs,uint64_t pc,int mode,int event)582 void xenoprof_log_event(struct vcpu *vcpu, const struct cpu_user_regs *regs,
583                         uint64_t pc, int mode, int event)
584 {
585     struct domain *d = vcpu->domain;
586     struct xenoprof_vcpu *v;
587     xenoprof_buf_t *buf;
588 
589     total_samples++;
590 
591     /* Ignore samples of un-monitored domains. */
592     if ( !is_profiled(d) )
593     {
594         others_samples++;
595         return;
596     }
597 
598     v = &d->xenoprof->vcpu[vcpu->vcpu_id];
599     if ( v->buffer == NULL )
600     {
601         invalid_buffer_samples++;
602         return;
603     }
604 
605     buf = v->buffer;
606 
607     /* Provide backtrace if requested. */
608     if ( backtrace_depth > 0 )
609     {
610         if ( xenoprof_buf_space(xenoprof_buf(d, buf, event_head),
611                                 xenoprof_buf(d, buf, event_tail),
612                                 v->event_size) < 2 )
613         {
614             xenoprof_buf(d, buf, lost_samples)++;
615             lost_samples++;
616             return;
617         }
618 
619         /* xenoprof_add_sample() will increment lost_samples on failure */
620         if ( !xenoprof_add_sample(d, v, XENOPROF_ESCAPE_CODE, mode,
621                                   XENOPROF_TRACE_BEGIN) )
622             return;
623     }
624 
625     if ( xenoprof_add_sample(d, v, pc, mode, event) )
626     {
627         if ( is_active(vcpu->domain) )
628             active_samples++;
629         else
630             passive_samples++;
631         if ( mode == 0 )
632             xenoprof_buf(d, buf, user_samples)++;
633         else if ( mode == 1 )
634             xenoprof_buf(d, buf, kernel_samples)++;
635         else
636             xenoprof_buf(d, buf, xen_samples)++;
637 
638     }
639 
640     if ( backtrace_depth > 0 )
641         xenoprof_backtrace(vcpu, regs, backtrace_depth, mode);
642 }
643 
644 
645 
xenoprof_op_init(XEN_GUEST_HANDLE_PARAM (void)arg)646 static int xenoprof_op_init(XEN_GUEST_HANDLE_PARAM(void) arg)
647 {
648     struct domain *d = current->domain;
649     struct xenoprof_init xenoprof_init;
650     int ret;
651 
652     if ( copy_from_guest(&xenoprof_init, arg, 1) )
653         return -EFAULT;
654 
655     if ( (ret = xenoprof_arch_init(&xenoprof_init.num_events,
656                                    xenoprof_init.cpu_type)) )
657         return ret;
658 
659     /* Only the hardware domain may become the primary profiler here because
660      * there is currently no cleanup of xenoprof_primary_profiler or associated
661      * profiling state when the primary profiling domain is shut down or
662      * crashes.  Once a better cleanup method is present, it will be possible to
663      * allow another domain to be the primary profiler.
664      */
665     xenoprof_init.is_primary =
666         ((xenoprof_primary_profiler == d) ||
667          ((xenoprof_primary_profiler == NULL) && is_hardware_domain(d)));
668     if ( xenoprof_init.is_primary )
669         xenoprof_primary_profiler = current->domain;
670 
671     return __copy_to_guest(arg, &xenoprof_init, 1) ? -EFAULT : 0;
672 }
673 
674 #define ret_t long
675 
676 #endif /* !COMPAT */
677 
xenoprof_op_get_buffer(XEN_GUEST_HANDLE_PARAM (void)arg)678 static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE_PARAM(void) arg)
679 {
680     struct xenoprof_get_buffer xenoprof_get_buffer;
681     struct domain *d = current->domain;
682     int ret;
683 
684     if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) )
685         return -EFAULT;
686 
687     /*
688      * We allocate xenoprof struct and buffers only at first time
689      * get_buffer is called. Memory is then kept until domain is destroyed.
690      */
691     if ( d->xenoprof == NULL )
692     {
693         ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0);
694         if ( ret < 0 )
695             return ret;
696     }
697     else
698         d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED;
699 
700     ret = share_xenoprof_page_with_guest(
701         d, virt_to_mfn(d->xenoprof->rawbuf), d->xenoprof->npages);
702     if ( ret < 0 )
703         return ret;
704 
705     xenoprof_reset_buf(d);
706 
707     xenoprof_get_buffer.nbuf = d->xenoprof->nbuf;
708     xenoprof_get_buffer.bufsize = d->xenoprof->bufsize;
709     if ( !paging_mode_translate(d) )
710         xenoprof_get_buffer.buf_gmaddr = __pa(d->xenoprof->rawbuf);
711     else
712         xenoprof_shared_gmfn_with_guest(
713             d, __pa(d->xenoprof->rawbuf), xenoprof_get_buffer.buf_gmaddr,
714             d->xenoprof->npages);
715 
716     return __copy_to_guest(arg, &xenoprof_get_buffer, 1) ? -EFAULT : 0;
717 }
718 
719 #define NONPRIV_OP(op) ( (op == XENOPROF_init)          \
720                       || (op == XENOPROF_enable_virq)   \
721                       || (op == XENOPROF_disable_virq)  \
722                       || (op == XENOPROF_get_buffer))
723 
do_xenoprof_op(int op,XEN_GUEST_HANDLE_PARAM (void)arg)724 ret_t do_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg)
725 {
726     int ret = 0;
727 
728     if ( (op < 0) || (op > XENOPROF_last_op) )
729     {
730         gdprintk(XENLOG_DEBUG, "invalid operation %d\n", op);
731         return -EINVAL;
732     }
733 
734     if ( !NONPRIV_OP(op) && (current->domain != xenoprof_primary_profiler) )
735     {
736         gdprintk(XENLOG_DEBUG, "denied privileged operation %d\n", op);
737         return -EPERM;
738     }
739 
740     ret = xsm_profile(XSM_HOOK, current->domain, op);
741     if ( ret )
742         return ret;
743 
744     spin_lock(&xenoprof_lock);
745 
746     switch ( op )
747     {
748     case XENOPROF_init:
749         ret = xenoprof_op_init(arg);
750         if ( (ret == 0) &&
751              (current->domain == xenoprof_primary_profiler) )
752             xenoprof_state = XENOPROF_INITIALIZED;
753         break;
754 
755     case XENOPROF_get_buffer:
756         if ( !acquire_pmu_ownership(PMU_OWNER_XENOPROF) )
757         {
758             ret = -EBUSY;
759             break;
760         }
761         ret = xenoprof_op_get_buffer(arg);
762         break;
763 
764     case XENOPROF_reset_active_list:
765         reset_active_list();
766         ret = 0;
767         break;
768 
769     case XENOPROF_reset_passive_list:
770         reset_passive_list();
771         ret = 0;
772         break;
773 
774     case XENOPROF_set_active:
775     {
776         domid_t domid;
777         if ( xenoprof_state != XENOPROF_INITIALIZED )
778         {
779             ret = -EPERM;
780             break;
781         }
782         if ( copy_from_guest(&domid, arg, 1) )
783         {
784             ret = -EFAULT;
785             break;
786         }
787         ret = add_active_list(domid);
788         break;
789     }
790 
791     case XENOPROF_set_passive:
792         if ( xenoprof_state != XENOPROF_INITIALIZED )
793         {
794             ret = -EPERM;
795             break;
796         }
797         ret = add_passive_list(arg);
798         break;
799 
800     case XENOPROF_reserve_counters:
801         if ( xenoprof_state != XENOPROF_INITIALIZED )
802         {
803             ret = -EPERM;
804             break;
805         }
806         ret = xenoprof_arch_reserve_counters();
807         if ( !ret )
808             xenoprof_state = XENOPROF_COUNTERS_RESERVED;
809         break;
810 
811     case XENOPROF_counter:
812         if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) ||
813              (adomains == 0) )
814         {
815             ret = -EPERM;
816             break;
817         }
818         ret = xenoprof_arch_counter(arg);
819         break;
820 
821     case XENOPROF_setup_events:
822         if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED )
823         {
824             ret = -EPERM;
825             break;
826         }
827         ret = xenoprof_arch_setup_events();
828         if ( !ret )
829             xenoprof_state = XENOPROF_READY;
830         break;
831 
832     case XENOPROF_enable_virq:
833     {
834         int i;
835 
836         if ( current->domain == xenoprof_primary_profiler )
837         {
838             if ( xenoprof_state != XENOPROF_READY )
839             {
840                 ret = -EPERM;
841                 break;
842             }
843             xenoprof_arch_enable_virq();
844             xenoprof_reset_stat();
845             for ( i = 0; i < pdomains; i++ )
846                 xenoprof_reset_buf(passive_domains[i]);
847         }
848         xenoprof_reset_buf(current->domain);
849         ret = set_active(current->domain);
850         break;
851     }
852 
853     case XENOPROF_start:
854         ret = -EPERM;
855         if ( (xenoprof_state == XENOPROF_READY) &&
856              (activated == adomains) )
857             ret = xenoprof_arch_start();
858         if ( ret == 0 )
859             xenoprof_state = XENOPROF_PROFILING;
860         break;
861 
862     case XENOPROF_stop:
863     {
864         struct domain *d;
865         struct vcpu *v;
866         int i;
867 
868         if ( xenoprof_state != XENOPROF_PROFILING )
869         {
870             ret = -EPERM;
871             break;
872         }
873         xenoprof_arch_stop();
874 
875         /* Flush remaining samples. */
876         for ( i = 0; i < adomains; i++ )
877         {
878             if ( !active_ready[i] )
879                 continue;
880             d = active_domains[i];
881             for_each_vcpu(d, v)
882                 send_guest_vcpu_virq(v, VIRQ_XENOPROF);
883         }
884         xenoprof_state = XENOPROF_READY;
885         break;
886     }
887 
888     case XENOPROF_disable_virq:
889     {
890         struct xenoprof *x;
891         if ( (xenoprof_state == XENOPROF_PROFILING) &&
892              (is_active(current->domain)) )
893         {
894             ret = -EPERM;
895             break;
896         }
897         if ( (ret = reset_active(current->domain)) != 0 )
898             break;
899         x = current->domain->xenoprof;
900         unshare_xenoprof_page_with_guest(x);
901         release_pmu_ownership(PMU_OWNER_XENOPROF);
902         break;
903     }
904 
905     case XENOPROF_release_counters:
906         ret = -EPERM;
907         if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) ||
908              (xenoprof_state == XENOPROF_READY) )
909         {
910             xenoprof_state = XENOPROF_INITIALIZED;
911             xenoprof_arch_release_counters();
912             xenoprof_arch_disable_virq();
913             reset_passive_list();
914             ret = 0;
915         }
916         break;
917 
918     case XENOPROF_shutdown:
919         ret = -EPERM;
920         if ( xenoprof_state == XENOPROF_INITIALIZED )
921         {
922             activated = 0;
923             adomains=0;
924             xenoprof_primary_profiler = NULL;
925             backtrace_depth=0;
926             ret = 0;
927         }
928         break;
929 
930     case XENOPROF_set_backtrace:
931         ret = 0;
932         if ( !xenoprof_backtrace_supported() )
933             ret = -EINVAL;
934         else if ( copy_from_guest(&backtrace_depth, arg, 1) )
935             ret = -EFAULT;
936         break;
937 
938     case XENOPROF_ibs_counter:
939         if ( (xenoprof_state != XENOPROF_COUNTERS_RESERVED) ||
940              (adomains == 0) )
941         {
942             ret = -EPERM;
943             break;
944         }
945         ret = xenoprof_arch_ibs_counter(arg);
946         break;
947 
948     case XENOPROF_get_ibs_caps:
949         ret = ibs_caps;
950         break;
951 
952     default:
953         ret = -ENOSYS;
954     }
955 
956     spin_unlock(&xenoprof_lock);
957 
958     if ( ret < 0 )
959         gdprintk(XENLOG_DEBUG, "operation %d failed: %d\n", op, ret);
960 
961     return ret;
962 }
963 
964 #if defined(CONFIG_COMPAT) && !defined(COMPAT)
965 #undef ret_t
966 #include "compat/xenoprof.c"
967 #endif
968 
969 /*
970  * Local variables:
971  * mode: C
972  * c-file-style: "BSD"
973  * c-basic-offset: 4
974  * tab-width: 4
975  * indent-tabs-mode: nil
976  * End:
977  */
978