1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <ddk/binding.h>
6 #include <ddk/device.h>
7 #include <ddk/driver.h>
8
9 #include <lib/zircon-internal/ktrace.h>
10 #include <zircon/syscalls.h>
11 #include <zircon/types.h>
12
13 #include <zircon/device/ktrace.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <threads.h>
19
ktrace_read(void * ctx,void * buf,size_t count,zx_off_t off,size_t * actual)20 static zx_status_t ktrace_read(void* ctx, void* buf, size_t count, zx_off_t off, size_t* actual) {
21 size_t length;
22 zx_status_t status = zx_ktrace_read(get_root_resource(), buf, off, count, &length);
23 if (status == ZX_OK) {
24 *actual = length;
25 }
26 return status;
27 }
28
ktrace_get_size(void * ctx)29 static zx_off_t ktrace_get_size(void* ctx) {
30 size_t size;
31 zx_status_t status = zx_ktrace_read(get_root_resource(), NULL, 0, 0, &size);
32 return status != ZX_OK ? (zx_off_t)status : (zx_off_t)size;
33 }
34
ktrace_ioctl(void * ctx,uint32_t op,const void * cmd,size_t cmdlen,void * reply,size_t max,size_t * out_actual)35 static zx_status_t ktrace_ioctl(void* ctx, uint32_t op,
36 const void* cmd, size_t cmdlen,
37 void* reply, size_t max, size_t* out_actual) {
38 switch (op) {
39 case IOCTL_KTRACE_GET_HANDLE: {
40 if (max < sizeof(zx_handle_t)) {
41 return ZX_ERR_BUFFER_TOO_SMALL;
42 }
43 //TODO: ktrace-only handle once resources are further along
44 zx_handle_t h;
45 zx_status_t status = zx_handle_duplicate(get_root_resource(), ZX_RIGHT_SAME_RIGHTS, &h);
46 if (status < 0) {
47 return status;
48 }
49 *((zx_handle_t*) reply) = h;
50 *out_actual = sizeof(zx_handle_t);
51 return ZX_OK;
52 }
53 case IOCTL_KTRACE_ADD_PROBE: {
54 char name[ZX_MAX_NAME_LEN];
55 if ((cmdlen >= ZX_MAX_NAME_LEN) || (cmdlen < 1) || (max != sizeof(uint32_t))) {
56 return ZX_ERR_INVALID_ARGS;
57 }
58 memcpy(name, cmd, cmdlen);
59 name[cmdlen] = 0;
60 zx_status_t status = zx_ktrace_control(get_root_resource(), KTRACE_ACTION_NEW_PROBE, 0, name);
61 if (status < 0) {
62 return status;
63 }
64 *((uint32_t*) reply) = status;
65 *out_actual = sizeof(uint32_t);
66 return ZX_OK;
67 }
68 case IOCTL_KTRACE_START: {
69 if (cmdlen != sizeof(uint32_t)) {
70 return ZX_ERR_INVALID_ARGS;
71 }
72 uint32_t group_mask = *(uint32_t *)cmd;
73 return zx_ktrace_control(get_root_resource(), KTRACE_ACTION_START, group_mask, NULL);
74 }
75 case IOCTL_KTRACE_STOP: {
76 zx_ktrace_control(get_root_resource(), KTRACE_ACTION_STOP, 0, NULL);
77 zx_ktrace_control(get_root_resource(), KTRACE_ACTION_REWIND, 0, NULL);
78 return ZX_OK;
79 }
80 default:
81 return ZX_ERR_INVALID_ARGS;
82 }
83 }
84
85 static zx_protocol_device_t ktrace_device_proto = {
86 .version = DEVICE_OPS_VERSION,
87 .read = ktrace_read,
88 .ioctl = ktrace_ioctl,
89 .get_size = ktrace_get_size,
90 };
91
ktrace_bind(void * ctx,zx_device_t * parent)92 static zx_status_t ktrace_bind(void* ctx, zx_device_t* parent) {
93 device_add_args_t args = {
94 .version = DEVICE_ADD_ARGS_VERSION,
95 .name = "ktrace",
96 .ops = &ktrace_device_proto,
97 };
98
99 zx_device_t* dev;
100 return device_add(parent, &args, &dev);
101 }
102
103 static zx_driver_ops_t ktrace_driver_ops = {
104 .version = DRIVER_OPS_VERSION,
105 .bind = ktrace_bind,
106 };
107
108 ZIRCON_DRIVER_BEGIN(ktrace, ktrace_driver_ops, "zircon", "0.1", 1)
109 BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MISC_PARENT),
110 ZIRCON_DRIVER_END(ktrace)
111