blob: 79f691f134d4a0c7063e22c28c57e779e38eb609 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#if defined(__x86_64__) || defined(__aarch64__) // entire file
#include <lib/perfmon.h>
#include <lib/zircon-internal/mtrace.h>
#include <arch/user_copy.h>
#include <object/process_dispatcher.h>
#include <object/vm_object_dispatcher.h>
#include "lib/mtrace.h"
#include "trace.h"
#define LOCAL_TRACE 0
zx_status_t mtrace_perfmon_control(uint32_t action, uint32_t options, user_inout_ptr<void> arg,
size_t size) {
LTRACEF("action %u, options 0x%x, arg %p, size 0x%zx\n", action, options, arg.get(), size);
switch (action) {
case MTRACE_PERFMON_GET_PROPERTIES: {
ArchPmuProperties props;
if (size != sizeof(props))
return ZX_ERR_INVALID_ARGS;
if (options != 0)
return ZX_ERR_INVALID_ARGS;
auto status = arch_perfmon_get_properties(&props);
if (status != ZX_OK)
return status;
status = arg.reinterpret<ArchPmuProperties>().copy_to_user(props);
if (status != ZX_OK)
return status;
return ZX_OK;
}
case MTRACE_PERFMON_INIT:
if (options != 0 || size != 0)
return ZX_ERR_INVALID_ARGS;
return arch_perfmon_init();
case MTRACE_PERFMON_ASSIGN_BUFFER: {
zx_pmu_buffer_t buffer;
if (size != sizeof(buffer))
return ZX_ERR_INVALID_ARGS;
zx_status_t status = arg.reinterpret<zx_pmu_buffer_t>().copy_from_user(&buffer);
if (status != ZX_OK)
return status;
// TODO(dje): Later need to rework to assign buffers to things
// like threads.
uint32_t cpu = MTRACE_PERFMON_OPTIONS_CPU(options);
if ((options & ~MTRACE_PERFMON_OPTIONS_CPU_MASK) != 0)
return ZX_ERR_INVALID_ARGS;
// lookup the VMO dispatcher from handle
// TODO(dje): Passing in a vmo from userspace, even from a device
// driver we control, to which we will write from kernel space, feels
// dodgey. Perhaps we should allocate the vmo here, but that put more
// of this driver in kernel space. Revisit.
auto up = ProcessDispatcher::GetCurrent();
fbl::RefPtr<VmObjectDispatcher> vmo;
zx_rights_t vmo_rights;
zx_rights_t needed_rights = ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE;
status =
up->handle_table().GetDispatcherWithRights(buffer.vmo, needed_rights, &vmo, &vmo_rights);
if (status != ZX_OK)
return status;
return arch_perfmon_assign_buffer(cpu, ktl::move(vmo->vmo()));
}
case MTRACE_PERFMON_STAGE_CONFIG: {
ArchPmuConfig config;
if (size != sizeof(config))
return ZX_ERR_INVALID_ARGS;
zx_status_t status = arg.reinterpret<ArchPmuConfig>().copy_from_user(&config);
if (status != ZX_OK)
return status;
if (options != 0)
return ZX_ERR_INVALID_ARGS;
return arch_perfmon_stage_config(&config);
}
case MTRACE_PERFMON_START:
if (options != 0 || size != 0)
return ZX_ERR_INVALID_ARGS;
return arch_perfmon_start();
case MTRACE_PERFMON_STOP:
if (options != 0 || size != 0)
return ZX_ERR_INVALID_ARGS;
arch_perfmon_stop();
return ZX_OK;
case MTRACE_PERFMON_FINI:
if (options != 0 || size != 0)
return ZX_ERR_INVALID_ARGS;
arch_perfmon_fini();
return ZX_OK;
default:
return ZX_ERR_INVALID_ARGS;
}
}
#endif // defined(__x86_64__) || defined(__aarch64__)