1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #ifdef __x86_64__ // entire file
8 
9 #include <inttypes.h>
10 
11 #include "lib/mtrace.h"
12 #include "trace.h"
13 
14 #include <arch/user_copy.h>
15 #include <object/process_dispatcher.h>
16 #include <object/vm_object_dispatcher.h>
17 
18 #include <lib/zircon-internal/mtrace.h>
19 
20 #include "arch/x86/perf_mon.h"
21 using zx_arch_pmu_properties_t = zx_x86_pmu_properties_t;
22 using zx_arch_pmu_config_t = zx_x86_pmu_config_t;
23 using zx_arch_pmu_buffer_t = zx_x86_pmu_buffer_t;
24 
25 #define LOCAL_TRACE 0
26 
mtrace_cpuperf_control(uint32_t action,uint32_t options,user_inout_ptr<void> arg,size_t size)27 zx_status_t mtrace_cpuperf_control(uint32_t action, uint32_t options,
28                                    user_inout_ptr<void> arg, size_t size) {
29     LTRACEF("action %u, options 0x%x, arg %p, size 0x%zx\n",
30             action, options, arg.get(), size);
31 
32     switch (action) {
33     case MTRACE_CPUPERF_GET_PROPERTIES: {
34         zx_arch_pmu_properties_t props;
35         if (size != sizeof(props))
36             return ZX_ERR_INVALID_ARGS;
37         if (options != 0)
38             return ZX_ERR_INVALID_ARGS;
39         auto status = arch_perfmon_get_properties(&props);
40         if (status != ZX_OK)
41             return status;
42         status = arg.reinterpret<zx_arch_pmu_properties_t>().copy_to_user(props);
43         if (status != ZX_OK)
44             return status;
45         return ZX_OK;
46     }
47 
48     case MTRACE_CPUPERF_INIT:
49         if (options != 0 || size != 0)
50             return ZX_ERR_INVALID_ARGS;
51         return arch_perfmon_init();
52 
53     case MTRACE_CPUPERF_ASSIGN_BUFFER: {
54         zx_arch_pmu_buffer_t buffer;
55         if (size != sizeof(buffer))
56             return ZX_ERR_INVALID_ARGS;
57         zx_status_t status = arg.reinterpret<zx_arch_pmu_buffer_t>().copy_from_user(&buffer);
58         if (status != ZX_OK)
59             return status;
60 
61         // TODO(dje): Later need to rework to assign buffers to things
62         // like threads.
63         uint32_t cpu = MTRACE_CPUPERF_OPTIONS_CPU(options);
64         if ((options & ~MTRACE_CPUPERF_OPTIONS_CPU_MASK) != 0)
65             return ZX_ERR_INVALID_ARGS;
66 
67         // lookup the VMO dispatcher from handle
68         // TODO(dje): Passing in a vmo from userspace, even from a device
69         // driver we control, to which we will write from kernel space, feels
70         // dodgey. Perhaps we should allocate the vmo here, but that put more
71         // of this driver in kernel space. Revisit.
72         auto up = ProcessDispatcher::GetCurrent();
73         fbl::RefPtr<VmObjectDispatcher> vmo;
74         zx_rights_t vmo_rights;
75         zx_rights_t needed_rights =
76             ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE;
77         status = up->GetDispatcherWithRights(buffer.vmo, needed_rights,
78                                              &vmo, &vmo_rights);
79         if (status != ZX_OK)
80             return status;
81 
82         return arch_perfmon_assign_buffer(cpu, ktl::move(vmo->vmo()));
83     }
84 
85     case MTRACE_CPUPERF_STAGE_CONFIG: {
86         zx_arch_pmu_config_t config;
87         if (size != sizeof(config))
88             return ZX_ERR_INVALID_ARGS;
89         zx_status_t status = arg.reinterpret<zx_arch_pmu_config_t>().copy_from_user(&config);
90         if (status != ZX_OK)
91             return status;
92         if (options != 0)
93             return ZX_ERR_INVALID_ARGS;
94         return arch_perfmon_stage_config(&config);
95     }
96 
97     case MTRACE_CPUPERF_START:
98         if (options != 0 || size != 0)
99             return ZX_ERR_INVALID_ARGS;
100         return arch_perfmon_start();
101 
102     case MTRACE_CPUPERF_STOP:
103         if (options != 0 || size != 0)
104             return ZX_ERR_INVALID_ARGS;
105         return arch_perfmon_stop();
106 
107     case MTRACE_CPUPERF_FINI:
108         if (options != 0 || size != 0)
109             return ZX_ERR_INVALID_ARGS;
110         return arch_perfmon_fini();
111 
112     default:
113         return ZX_ERR_INVALID_ARGS;
114     }
115 }
116 
117 #endif
118