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
22#define LOCAL_TRACE 0
23
24zx_status_t mtrace_cpuperf_control(uint32_t action, uint32_t options,
25                                   user_inout_ptr<void> arg, size_t size) {
26    TRACEF("action %u, options 0x%x, arg %p, size 0x%zx\n",
27           action, options, arg.get(), size);
28
29    switch (action) {
30    case MTRACE_CPUPERF_GET_PROPERTIES: {
31        zx_x86_ipm_properties_t props;
32        if (size != sizeof(props))
33            return ZX_ERR_INVALID_ARGS;
34        if (options != 0)
35            return ZX_ERR_INVALID_ARGS;
36        auto status = x86_ipm_get_properties(&props);
37        if (status != ZX_OK)
38            return status;
39        status = arg.reinterpret<zx_x86_ipm_properties_t>().copy_to_user(props);
40        if (status != ZX_OK)
41            return status;
42        return ZX_OK;
43    }
44
45    case MTRACE_CPUPERF_INIT:
46        if (options != 0 || size != 0)
47            return ZX_ERR_INVALID_ARGS;
48        return x86_ipm_init();
49
50    case MTRACE_CPUPERF_ASSIGN_BUFFER: {
51        zx_x86_ipm_buffer_t buffer;
52        if (size != sizeof(buffer))
53            return ZX_ERR_INVALID_ARGS;
54        zx_status_t status = arg.reinterpret<zx_x86_ipm_buffer_t>().copy_from_user(&buffer);
55        if (status != ZX_OK)
56            return status;
57
58        // TODO(dje): Later need to rework to assign buffers to things
59        // like threads.
60        uint32_t cpu = MTRACE_CPUPERF_OPTIONS_CPU(options);
61        if ((options & ~MTRACE_CPUPERF_OPTIONS_CPU_MASK) != 0)
62            return ZX_ERR_INVALID_ARGS;
63
64        // lookup the VMO dispatcher from handle
65        // TODO(dje): Passing in a vmo from userspace, even from a device
66        // driver we control, to which we will write from kernel space, feels
67        // dodgey. Perhaps we should allocate the vmo here, but that put more
68        // of this driver in kernel space. Revisit.
69        auto up = ProcessDispatcher::GetCurrent();
70        fbl::RefPtr<VmObjectDispatcher> vmo;
71        zx_rights_t vmo_rights;
72        zx_rights_t needed_rights =
73            ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE;
74        status = up->GetDispatcherWithRights(buffer.vmo, needed_rights,
75                                             &vmo, &vmo_rights);
76        if (status != ZX_OK)
77            return status;
78
79        return x86_ipm_assign_buffer(cpu, fbl::move(vmo->vmo()));
80    }
81
82    case MTRACE_CPUPERF_STAGE_CONFIG: {
83        zx_x86_ipm_config_t config;
84        if (size != sizeof(config))
85            return ZX_ERR_INVALID_ARGS;
86        zx_status_t status = arg.reinterpret<zx_x86_ipm_config_t>().copy_from_user(&config);
87        if (status != ZX_OK)
88            return status;
89        if (options != 0)
90            return ZX_ERR_INVALID_ARGS;
91        TRACEF("action %u, global_ctrl 0x%" PRIx64 "\n",
92               action, config.global_ctrl);
93        return x86_ipm_stage_config(&config);
94    }
95
96    case MTRACE_CPUPERF_START:
97        if (options != 0 || size != 0)
98            return ZX_ERR_INVALID_ARGS;
99        return x86_ipm_start();
100
101    case MTRACE_CPUPERF_STOP:
102        if (options != 0 || size != 0)
103            return ZX_ERR_INVALID_ARGS;
104        return x86_ipm_stop();
105
106    case MTRACE_CPUPERF_FINI:
107        if (options != 0 || size != 0)
108            return ZX_ERR_INVALID_ARGS;
109        return x86_ipm_fini();
110
111    default:
112        return ZX_ERR_INVALID_ARGS;
113    }
114}
115
116#endif
117