summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2021-12-13 23:40:04 +0100
committerEugene Syromyatnikov <evgsyr@gmail.com>2021-12-13 23:40:04 +0100
commit7e6e42c2c11d43811ca0a83b496d526bd7ef4c08 (patch)
treebe1f5654efc0a7a8c21b536a91d50621ba4d7a5b
parenta6a47cff55840a6dc2f1f27456c263938e877299 (diff)
downloadstrace-7e6e42c2c11d43811ca0a83b496d526bd7ef4c08.tar.gz
Implement COUNTER_* ioctl decoding
-rw-r--r--bundled/Makefile.am1
-rw-r--r--bundled/linux/include/uapi/linux/counter.h154
-rw-r--r--src/counter_ioctl.c70
-rw-r--r--src/defs.h1
-rw-r--r--src/ioctl.c2
-rw-r--r--src/xlat/counter_ioctl_component_types.in9
-rw-r--r--src/xlat/counter_ioctl_event_types.in8
-rw-r--r--src/xlat/counter_ioctl_scopes.in6
8 files changed, 251 insertions, 0 deletions
diff --git a/bundled/Makefile.am b/bundled/Makefile.am
index aaa8942ed..7ccec1ea2 100644
--- a/bundled/Makefile.am
+++ b/bundled/Makefile.am
@@ -28,6 +28,7 @@ EXTRA_DIST = \
linux/include/uapi/linux/btrfs_tree.h \
linux/include/uapi/linux/close_range.h \
linux/include/uapi/linux/const.h \
+ linux/include/uapi/linux/counter.h \
linux/include/uapi/linux/cryptouser.h \
linux/include/uapi/linux/dcbnl.h \
linux/include/uapi/linux/dm-ioctl.h \
diff --git a/bundled/linux/include/uapi/linux/counter.h b/bundled/linux/include/uapi/linux/counter.h
new file mode 100644
index 000000000..e23962d91
--- /dev/null
+++ b/bundled/linux/include/uapi/linux/counter.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Userspace ABI for Counter character devices
+ * Copyright (C) 2020 William Breathitt Gray
+ */
+#ifndef _COUNTER_H_
+#define _COUNTER_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* Component type definitions */
+enum counter_component_type {
+ COUNTER_COMPONENT_NONE,
+ COUNTER_COMPONENT_SIGNAL,
+ COUNTER_COMPONENT_COUNT,
+ COUNTER_COMPONENT_FUNCTION,
+ COUNTER_COMPONENT_SYNAPSE_ACTION,
+ COUNTER_COMPONENT_EXTENSION,
+};
+
+/* Component scope definitions */
+enum counter_scope {
+ COUNTER_SCOPE_DEVICE,
+ COUNTER_SCOPE_SIGNAL,
+ COUNTER_SCOPE_COUNT,
+};
+
+/**
+ * struct counter_component - Counter component identification
+ * @type: component type (one of enum counter_component_type)
+ * @scope: component scope (one of enum counter_scope)
+ * @parent: parent ID (matching the ID suffix of the respective parent sysfs
+ * path as described by the ABI documentation file
+ * Documentation/ABI/testing/sysfs-bus-counter)
+ * @id: component ID (matching the ID provided by the respective *_component_id
+ * sysfs attribute of the desired component)
+ *
+ * For example, if the Count 2 ceiling extension of Counter device 4 is desired,
+ * set type equal to COUNTER_COMPONENT_EXTENSION, scope equal to
+ * COUNTER_COUNT_SCOPE, parent equal to 2, and id equal to the value provided by
+ * the respective /sys/bus/counter/devices/counter4/count2/ceiling_component_id
+ * sysfs attribute.
+ */
+struct counter_component {
+ __u8 type;
+ __u8 scope;
+ __u8 parent;
+ __u8 id;
+};
+
+/* Event type definitions */
+enum counter_event_type {
+ /* Count value increased past ceiling */
+ COUNTER_EVENT_OVERFLOW,
+ /* Count value decreased past floor */
+ COUNTER_EVENT_UNDERFLOW,
+ /* Count value increased past ceiling, or decreased past floor */
+ COUNTER_EVENT_OVERFLOW_UNDERFLOW,
+ /* Count value reached threshold */
+ COUNTER_EVENT_THRESHOLD,
+ /* Index signal detected */
+ COUNTER_EVENT_INDEX,
+};
+
+/**
+ * struct counter_watch - Counter component watch configuration
+ * @component: component to watch when event triggers
+ * @event: event that triggers (one of enum counter_event_type)
+ * @channel: event channel (typically 0 unless the device supports concurrent
+ * events of the same type)
+ */
+struct counter_watch {
+ struct counter_component component;
+ __u8 event;
+ __u8 channel;
+};
+
+/*
+ * Queues a Counter watch for the specified event.
+ *
+ * The queued watches will not be applied until COUNTER_ENABLE_EVENTS_IOCTL is
+ * called.
+ */
+#define COUNTER_ADD_WATCH_IOCTL _IOW(0x3E, 0x00, struct counter_watch)
+/*
+ * Enables monitoring the events specified by the Counter watches that were
+ * queued by COUNTER_ADD_WATCH_IOCTL.
+ *
+ * If events are already enabled, the new set of watches replaces the old one.
+ * Calling this ioctl also has the effect of clearing the queue of watches added
+ * by COUNTER_ADD_WATCH_IOCTL.
+ */
+#define COUNTER_ENABLE_EVENTS_IOCTL _IO(0x3E, 0x01)
+/*
+ * Stops monitoring the previously enabled events.
+ */
+#define COUNTER_DISABLE_EVENTS_IOCTL _IO(0x3E, 0x02)
+
+/**
+ * struct counter_event - Counter event data
+ * @timestamp: best estimate of time of event occurrence, in nanoseconds
+ * @value: component value
+ * @watch: component watch configuration
+ * @status: return status (system error number)
+ */
+struct counter_event {
+ __aligned_u64 timestamp;
+ __aligned_u64 value;
+ struct counter_watch watch;
+ __u8 status;
+};
+
+/* Count direction values */
+enum counter_count_direction {
+ COUNTER_COUNT_DIRECTION_FORWARD,
+ COUNTER_COUNT_DIRECTION_BACKWARD,
+};
+
+/* Count mode values */
+enum counter_count_mode {
+ COUNTER_COUNT_MODE_NORMAL,
+ COUNTER_COUNT_MODE_RANGE_LIMIT,
+ COUNTER_COUNT_MODE_NON_RECYCLE,
+ COUNTER_COUNT_MODE_MODULO_N,
+};
+
+/* Count function values */
+enum counter_function {
+ COUNTER_FUNCTION_INCREASE,
+ COUNTER_FUNCTION_DECREASE,
+ COUNTER_FUNCTION_PULSE_DIRECTION,
+ COUNTER_FUNCTION_QUADRATURE_X1_A,
+ COUNTER_FUNCTION_QUADRATURE_X1_B,
+ COUNTER_FUNCTION_QUADRATURE_X2_A,
+ COUNTER_FUNCTION_QUADRATURE_X2_B,
+ COUNTER_FUNCTION_QUADRATURE_X4,
+};
+
+/* Signal values */
+enum counter_signal_level {
+ COUNTER_SIGNAL_LEVEL_LOW,
+ COUNTER_SIGNAL_LEVEL_HIGH,
+};
+
+/* Action mode values */
+enum counter_synapse_action {
+ COUNTER_SYNAPSE_ACTION_NONE,
+ COUNTER_SYNAPSE_ACTION_RISING_EDGE,
+ COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
+ COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
+};
+
+#endif /* _COUNTER_H_ */
diff --git a/src/counter_ioctl.c b/src/counter_ioctl.c
new file mode 100644
index 000000000..5ed2fb750
--- /dev/null
+++ b/src/counter_ioctl.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <linux/ioctl.h>
+#include <linux/counter.h>
+
+#include "xlat/counter_ioctl_component_types.h"
+#include "xlat/counter_ioctl_event_types.h"
+#include "xlat/counter_ioctl_scopes.h"
+
+
+static void
+print_struct_counter_component(const struct counter_component *const cc)
+{
+ tprint_struct_begin();
+ PRINT_FIELD_XVAL(*cc, type, counter_ioctl_component_types,
+ "COUNTER_COMPONENT_???");
+ tprint_struct_next();
+ PRINT_FIELD_XVAL(*cc, type, counter_ioctl_component_scopes,
+ "COUNTER_SCOPE_???");
+ tprint_struct_next();
+ PRINT_FIELD_U(*cc, parent);
+ tprint_struct_next();
+ PRINT_FIELD_U(*cc, id);
+ tprint_struct_end();
+}
+
+static void
+print_struct_counter_watch(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ CHECK_IOCTL_SIZE(COUNTER_ADD_WATCH_IOCTL, 6);
+ CHECK_TYPE_SIZE(struct counter_watch, 6);
+ struct counter_watch w;
+
+ if (umove_or_printaddr(tcp, addr, &w))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_OBJ_PTR(w, component, print_struct_counter_component);
+ tprint_struct_next();
+ PRINT_FIELD_XVAL(w, event, counter_ioctl_events,
+ "COUNTER_EVENT_???");
+ tprint_struct_next();
+ PRINT_FIELD_U(w, channel);
+ tprint_struct_end();
+}
+
+int
+counter_ioctl(struct tcb *const tcp, const unsigned int code,
+ const kernel_ulong_t arg)
+{
+ switch (code) {
+ case COUNTER_ADD_WATCH_IOCTL:
+ tprint_arg_next();
+ print_struct_counter_watch(tcp, arg);
+
+ case COUNTER_ENABLE_EVENTS_IOCTL:
+ case COUNTER_DISABLE_EVENTS_IOCTL:
+ return RVAL_IOCTL_DECODED;
+
+ default:
+ return RVAL_DECODED;
+ }
+}
diff --git a/src/defs.h b/src/defs.h
index c454b0b09..482bc236f 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -1356,6 +1356,7 @@ extern int \
name ## _ioctl(struct tcb *, unsigned int request, kernel_ulong_t arg) \
/* End of DECL_IOCTL definition. */
+DECL_IOCTL(counter);
DECL_IOCTL(dm);
DECL_IOCTL(evdev);
DECL_IOCTL(fs_0x94);
diff --git a/src/ioctl.c b/src/ioctl.c
index 1965af32c..d75c04829 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -362,6 +362,8 @@ ioctl_decode(struct tcb *tcp)
return perf_ioctl(tcp, code, arg);
case '=': /* 0x3d */
return ptp_ioctl(tcp, code, arg);
+ case '>': /* 0x3e */
+ return counter_ioctl(tcp, code, arg);
case 'E':
return evdev_ioctl(tcp, code, arg);
case 'I':
diff --git a/src/xlat/counter_ioctl_component_types.in b/src/xlat/counter_ioctl_component_types.in
new file mode 100644
index 000000000..a99ccb544
--- /dev/null
+++ b/src/xlat/counter_ioctl_component_types.in
@@ -0,0 +1,9 @@
+#enum
+#value_indexed
+#unconditional
+COUNTER_COMPONENT_NONE 0
+COUNTER_COMPONENT_SIGNAL 1
+COUNTER_COMPONENT_COUNT 2
+COUNTER_COMPONENT_FUNCTION 3
+COUNTER_COMPONENT_SYNAPSE_ACTION 4
+COUNTER_COMPONENT_EXTENSION 5
diff --git a/src/xlat/counter_ioctl_event_types.in b/src/xlat/counter_ioctl_event_types.in
new file mode 100644
index 000000000..fa5d1d406
--- /dev/null
+++ b/src/xlat/counter_ioctl_event_types.in
@@ -0,0 +1,8 @@
+#enum
+#value_indexed
+#unconditional
+COUNTER_EVENT_OVERFLOW 0
+COUNTER_EVENT_UNDERFLOW 1
+COUNTER_EVENT_OVERFLOW_UNDERFLOW 2
+COUNTER_EVENT_THRESHOLD 3
+COUNTER_EVENT_INDEX 4
diff --git a/src/xlat/counter_ioctl_scopes.in b/src/xlat/counter_ioctl_scopes.in
new file mode 100644
index 000000000..cd115716f
--- /dev/null
+++ b/src/xlat/counter_ioctl_scopes.in
@@ -0,0 +1,6 @@
+#enum
+#value_indexed
+#unconditional
+COUNTER_SCOPE_DEVICE 0
+COUNTER_SCOPE_SIGNAL 1
+COUNTER_SCOPE_COUNT 2