summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2016-06-19 04:57:39 +0200
committerSuren A. Chilingaryan <csa@suren.me>2016-06-19 04:57:39 +0200
commitce7360bfa4cdf51bf46d5cc645a67c4751b9731a (patch)
tree4bb263eabd2237d0f9d939dd18c8d0ecffd53118
downloadnvtrace-ce7360bfa4cdf51bf46d5cc645a67c4751b9731a.tar.gz
nvtrace-ce7360bfa4cdf51bf46d5cc645a67c4751b9731a.tar.bz2
nvtrace-ce7360bfa4cdf51bf46d5cc645a67c4751b9731a.tar.xz
nvtrace-ce7360bfa4cdf51bf46d5cc645a67c4751b9731a.zip
Initial import
-rw-r--r--.gitignore16
-rw-r--r--nvtrace.c166
-rw-r--r--test.c153
3 files changed, 335 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..60901a5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Makefile
+cmake_install.cmake
+install_manifest.txt
+CTestTestfile.cmake
+test
+*.cmd
+*.ko
+*.mod.c
+*.mod.o
+Module.symvers
+modules.order
+.tmp_versions
+*.o
diff --git a/nvtrace.c b/nvtrace.c
new file mode 100644
index 0000000..2f54ae8
--- /dev/null
+++ b/nvtrace.c
@@ -0,0 +1,166 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#include <linux/fs.h>
+#include <linux/device.h>
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Suren A. Chilingaryan <csa@suren.me>");
+MODULE_DESCRIPTION("NVIDIA Driver Tracer");
+MODULE_VERSION("0.0.1");
+
+
+#if !defined(CONFIG_X86) || !defined(CONFIG_X86_64)
+# error "Only x86-64 platform is currently supported"
+#endif
+
+DEFINE_SEMAPHORE(nv_sem);
+static spinlock_t nv_lock;
+static int nvtrace_enabled = 0;
+
+static int nv_state = 0;
+static unsigned nv_last_user = 0;
+static unsigned nv_last_buffer = 0;
+
+ // DS: we need to do it per pid
+static int handler_pre(struct kprobe *p, struct pt_regs *regs)
+{
+ char *logstr;
+ int pos, size;
+ int cmd = regs->dx&0xFF;
+
+ switch (cmd) {
+ case 0x4a:
+ size = 0xb0;
+ break;
+ case 0x57:
+ size = 0x38;
+ break;
+ case 0x2a:
+ size = 0x20;
+ break;
+ default:
+ size = 4;
+ }
+
+ logstr = kmalloc(9 * (size / 4), GFP_KERNEL);
+ if (logstr) {
+ for (pos = 0; (pos + 4) <= size; pos += 4)
+ sprintf(logstr + 9 * (pos / 4), " %08x", *(uint32_t*)(regs->cx + pos));
+ printk(KERN_INFO " cmd = 0x%lx: %s\n", regs->dx, logstr);
+ kfree(logstr);
+ }
+
+/*
+ printk(KERN_INFO " cmd = 0x%lx:", regs->dx);
+ for (pos = 0; (pos + 4) <= size; pos += 4) {
+ printk(KERN_INFO " %08x", *(uint32_t*)(regs->cx + pos));
+ }
+ printk(KERN_INFO "\n");
+*/
+
+/* printk(KERN_INFO
+ " cmd = 0x%lx: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ regs->dx,
+ *(uint32_t*)(regs->cx + 0x00), *(uint32_t*)(regs->cx + 0x04), *(uint32_t*)(regs->cx + 0x08), *(uint32_t*)(regs->cx + 0x0C),
+ *(uint32_t*)(regs->cx + 0x10), *(uint32_t*)(regs->cx + 0x14), *(uint32_t*)(regs->cx + 0x18), *(uint32_t*)(regs->cx + 0x1C)
+ );*/
+
+ if ((nv_state == 0x4a)&&(cmd == 0x57)) {
+ nv_last_user = *(uint32_t*)regs->cx;
+ nv_last_buffer = *(uint32_t*)(regs->cx + 0x0C);
+
+ printk(KERN_INFO "cmd = 0x%lx, userid = 0x%x, bufferid = 0x%x\n", regs->dx, nv_last_user, nv_last_buffer);
+ }
+ nv_state = cmd;
+
+ return 0;
+}
+
+static struct kprobe nv_curprobe, nv_probe = {
+ .symbol_name = "nvidia_ioctl",
+ .pre_handler = handler_pre
+};
+
+
+static ssize_t nv_enable_show(struct class *cls, struct class_attribute *attr, char *buf) {
+ sprintf(buf, "%d", nvtrace_enabled);
+ return 1;
+}
+
+static ssize_t nv_enable_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count) {
+ int ret;
+ int enable = 0;
+
+ if ((sscanf(buf, "%d", &enable) != 1)||(enable < 0)||(enable > 1))
+ return -EINVAL;
+
+ if (down_interruptible(&nv_sem))
+ return -EINVAL;
+
+ if (enable != nvtrace_enabled) {
+ if (enable) {
+ nv_curprobe = nv_probe;
+
+ ret = register_kprobe(&nv_curprobe);
+ if (ret < 0) {
+ up(&nv_sem);
+ printk(KERN_ERR "register_kprobe failed, returned %d\n", ret);
+ return ret;
+ }
+ printk(KERN_INFO "Planted kprobe at %p\n", nv_curprobe.addr);
+ } else {
+ unregister_kprobe(&nv_curprobe);
+ printk(KERN_INFO "kprobe at %p unregistered\n", nv_curprobe.addr);
+ }
+ nvtrace_enabled = enable;
+ }
+ up(&nv_sem);
+
+ return count;
+}
+
+static ssize_t nv_user_show(struct class *cls, struct class_attribute *attr, char *buf) {
+ sprintf(buf, "0x%x", nv_last_user);
+ return strlen(buf);
+}
+
+static ssize_t nv_buffer_show(struct class *cls, struct class_attribute *attr, char *buf) {
+ sprintf(buf, "0x%x", nv_last_buffer);
+ return strlen(buf);
+}
+
+static struct class_attribute nv_attrs[] = {
+ __ATTR(enable, S_IRUGO|S_IWUSR, nv_enable_show, nv_enable_store),
+ __ATTR(user, S_IRUGO, nv_user_show, NULL),
+ __ATTR(buffer, S_IRUGO, nv_buffer_show, NULL),
+ __ATTR_NULL
+};
+
+static struct class nv_class = {
+ .name = "nvtrace",
+ .owner = THIS_MODULE,
+ .class_attrs = nv_attrs
+};
+
+static int __init nvtrace_init(void)
+{
+ spin_lock_init(&nv_lock);
+
+ return class_register(&nv_class);
+}
+
+static void __exit nvtrace_exit(void)
+{
+ class_unregister(&nv_class);
+
+ if (nvtrace_enabled) {
+ unregister_kprobe(&nv_curprobe);
+ }
+}
+
+module_init(nvtrace_init)
+module_exit(nvtrace_exit)
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..f9805d8
--- /dev/null
+++ b/test.c
@@ -0,0 +1,153 @@
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "CL/cl.h"
+#include "CL/cl_ext.h"
+
+
+
+#define ITERS 1l
+#define DATA_SIZE (16384)
+
+
+#define CL_CHECK_STATUS(error) { \
+ if ((error) != CL_SUCCESS) fprintf (stderr, "OpenCL error <%s:%i>: %i\n", __FILE__, __LINE__, (error)); }
+
+
+int sysfs_write(const char *path, const char *arg) {
+ int err;
+
+ FILE *f = fopen(path, "w");
+ if (!f) return -ENOENT;
+
+ err = (fprintf(f, "%s", arg) < 1);
+
+ fclose(f);
+
+ return err;
+}
+
+int sysfs_read(const char *path, size_t size, char *arg) {
+ int err = 0;
+ size_t bytes;
+
+ FILE *f = fopen(path, "r");
+ if (!f) return -ENOENT;
+
+ bytes = fread((void*)arg, 1, size - 1, f);
+ if (bytes == 0) err = EIO;
+ else arg[bytes] = 0;
+
+ fclose(f);
+
+ return err;
+}
+
+
+int sysfs_write_int(const char *path, long arg) {
+ char s[16];
+ sprintf(s, "%d", arg);
+ return sysfs_write(path, s);
+}
+
+long sysfs_read_int(const char *path, int *reterr) {
+ int err;
+ char s[32];
+
+ long res = 0;
+
+ err = sysfs_read(path, 32, s);
+ if (!err) {
+ if (s[1] == 'x') {
+ err = (sscanf(s + 2, "%lx", &res) < 1);
+ } else {
+ err = (sscanf(s, "%lu", &res) < 1);
+ }
+ }
+
+ if (reterr) *reterr = err;
+ return res;
+}
+
+
+int main(void)
+{
+ int i;
+ size_t work_size = 1;
+
+ cl_context context;
+ cl_command_queue command_queue;
+ cl_int err;
+ cl_uint num_of_platforms=0;
+ cl_platform_id platform_id;
+ cl_device_id device_id;
+ cl_uint num_of_devices=0;
+ cl_mem input;//, output, host;
+ cl_event event;
+
+ cl_int status;
+ cl_command_type type;
+ size_t res_size;
+
+ uint32_t check;
+
+ CL_CHECK_STATUS(clGetPlatformIDs(1, &platform_id, &num_of_platforms));
+
+ CL_CHECK_STATUS(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id,&num_of_devices));
+
+ cl_context_properties properties[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties) platform_id, 0 };
+ context = clCreateContext(properties, 1, &device_id, NULL,NULL, &err);
+ CL_CHECK_STATUS(err);
+
+ command_queue = clCreateCommandQueue(context, device_id, 0, &err);
+ CL_CHECK_STATUS(err);
+
+ // CL_MEM_ALLOC_HOST_PTR does not help to access the data directly
+
+
+ sysfs_write_int("/sys/class/nvtrace/enable", 1);
+ input = clCreateBuffer(context, CL_MEM_READ_WRITE/*|CL_MEM_ALLOC_HOST_PTR*/, DATA_SIZE, NULL, &err); CL_CHECK_STATUS(err);
+ CL_CHECK_STATUS (clEnqueueWriteBuffer (command_queue, input, CL_TRUE, 0, 4, &i, 0, NULL, NULL));
+ sysfs_write_int("/sys/class/nvtrace/enable", 0);
+
+ uint32_t nv_user = sysfs_read_int("/sys/class/nvtrace/user", NULL);
+ uint32_t nv_buffer = sysfs_read_int("/sys/class/nvtrace/buffer", NULL);
+
+ printf("Detected context & buffer: %x %x\n", nv_user, nv_buffer);
+
+ int nvfd = open("/dev/nvidia0", O_RDWR);
+ if (nvfd >= 0) {
+ uint32_t gpu_method_param = nv_buffer;
+ uint32_t gpu_method[8] = {
+ nv_user,
+ 0x5c00000eu,
+ 0x503c0104u,
+ 0x00000000u,
+ 0,
+ 0,
+ 0x00000004u,
+ 0x00000000u
+ };
+
+ ((uint64_t*)gpu_method)[2] = (uint64_t)&gpu_method_param;
+
+ sysfs_write_int("/sys/class/nvtrace/enable", 1);
+ if (ioctl(nvfd, 0xc020462a, gpu_method) < 0)
+ printf(" ==> Error communicating with nvidia device, errno %i\n", errno);
+ sysfs_write_int("/sys/class/nvtrace/enable", 0);
+
+ close(nvfd);
+ }
+
+ clReleaseMemObject(input);
+ clReleaseCommandQueue(command_queue);
+ clReleaseContext(context);
+}