1 // Copyright 2016 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 <assert.h>
10 #include <inttypes.h>
11 
12 #include "lib/mtrace.h"
13 #include "trace.h"
14 
15 #include <object/process_dispatcher.h>
16 #include <lib/zircon-internal/mtrace.h>
17 #include <lib/zircon-internal/device/cpu-trace/intel-pt.h>
18 
19 #include "arch/x86/proc_trace.h"
20 
21 #define LOCAL_TRACE 0
22 
23 static_assert(IPT_MAX_NUM_TRACES >= SMP_MAX_CPUS, "");
24 
mtrace_insntrace_control(uint32_t action,uint32_t options,user_inout_ptr<void> arg,size_t size)25 zx_status_t mtrace_insntrace_control(uint32_t action, uint32_t options,
26                                      user_inout_ptr<void> arg, size_t size) {
27     TRACEF("action %u, options 0x%x, arg %p, size 0x%zx\n",
28            action, options, arg.get(), size);
29 
30     switch (action) {
31     case MTRACE_INSNTRACE_ALLOC_TRACE: {
32         if (options != 0)
33             return ZX_ERR_INVALID_ARGS;
34         ioctl_insntrace_trace_config_t config;
35         if (size != sizeof(config))
36             return ZX_ERR_INVALID_ARGS;
37         zx_status_t status = arg.reinterpret<ioctl_insntrace_trace_config_t>().copy_from_user(&config);
38         if (status != ZX_OK)
39             return status;
40         TRACEF("action %u, mode %u, num traces %u\n", action, config.mode, config.num_traces);
41         if (config.num_traces > IPT_MAX_NUM_TRACES)
42             return ZX_ERR_INVALID_ARGS;
43         switch (config.mode) {
44         case IPT_MODE_CPUS:
45             if (config.num_traces != arch_max_num_cpus())
46                 return ZX_ERR_INVALID_ARGS;
47             return x86_ipt_alloc_trace(IPT_TRACE_CPUS, config.num_traces);
48         case IPT_MODE_THREADS:
49             return x86_ipt_alloc_trace(IPT_TRACE_THREADS, config.num_traces);
50         default:
51             return ZX_ERR_INVALID_ARGS;
52         }
53     }
54 
55     case MTRACE_INSNTRACE_FREE_TRACE:
56         if (options != 0 || size != 0)
57             return ZX_ERR_INVALID_ARGS;
58         return x86_ipt_free_trace();
59 
60     case MTRACE_INSNTRACE_STAGE_TRACE_DATA: {
61         zx_x86_pt_regs_t regs;
62         if (size != sizeof(regs))
63             return ZX_ERR_INVALID_ARGS;
64         zx_status_t status = arg.reinterpret<zx_x86_pt_regs_t>().copy_from_user(&regs);
65         if (status != ZX_OK)
66             return status;
67         zx_itrace_buffer_descriptor_t descriptor = options;
68         TRACEF("action %u, descriptor %u, ctl 0x%" PRIx64 ", output_base 0x%" PRIx64 "\n",
69                action, descriptor, regs.ctl, regs.output_base);
70         return x86_ipt_stage_trace_data(descriptor, &regs);
71     }
72 
73     case MTRACE_INSNTRACE_GET_TRACE_DATA: {
74         zx_x86_pt_regs_t regs;
75         if (size != sizeof(regs))
76             return ZX_ERR_INVALID_ARGS;
77         zx_itrace_buffer_descriptor_t descriptor = options;
78         auto status = x86_ipt_get_trace_data(descriptor, &regs);
79         if (status != ZX_OK)
80             return status;
81         TRACEF("action %u, descriptor %u, ctl 0x%" PRIx64 ", output_base 0x%" PRIx64 "\n",
82                action, descriptor, regs.ctl, regs.output_base);
83         status = arg.reinterpret<zx_x86_pt_regs_t>().copy_to_user(regs);
84         if (status != ZX_OK)
85             return status;
86         return ZX_OK;
87     }
88 
89     case MTRACE_INSNTRACE_START:
90         if (options != 0 || size != 0)
91             return ZX_ERR_INVALID_ARGS;
92         return x86_ipt_start();
93 
94     case MTRACE_INSNTRACE_STOP:
95         if (options != 0 || size != 0)
96             return ZX_ERR_INVALID_ARGS;
97         return x86_ipt_stop();
98 
99     default:
100         return ZX_ERR_INVALID_ARGS;
101     }
102 }
103 
104 #endif
105