diff options
-rw-r--r-- | .gitignore | 16 | ||||
-rw-r--r-- | nvtrace.c | 166 | ||||
-rw-r--r-- | test.c | 153 |
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) @@ -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); +} |