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