免责声明:

免责声明:

我正在尝试编辑/proc/devices-tree 内的一个文件,但我无法这样做,我得到:

“权限被拒绝”或“输入/输出错误”。

我尝试了所有可能的编辑器组合chownchmod甚至sudo dd。我还知道要以十六进制写入的确切内存位置7000c400。我需要替换那里的 4 个字节,有什么方法可以帮助我实现这一点吗?

编辑:我尝试这样做想要达到什么目的?

  • 我有一个Jetson-TK1董事会和i2c总线设置为默认的400kHz,但我想以 运行它100kHz。我想我可以通过更改设备树结构并重新编译来实现这一点,但重新编译是一个更大的麻烦,因为我使用的内核不是标准内核(nvidia 不提供标准内核)。

    我曾在某处读到,在 Linux 中几乎所有东西都是文件形式。因此,我查找了一番,找到了一个包含 4 个字节的文件,其值为400000,我认为更改此文件会改变频率。

  • 现在真正的问题是我无法改变它(我认为我是一个足够优秀的用户,据我所知,如果内存中有东西并且我有各种密码,我应该能够更改它。我搞砸了某件事这一事实不是问题)。我尝试了所有我知道的可能方法(正如我在问题中添加的那样)。那么我该怎么做呢?

答案1

我研究这个问题主要是为了好玩和学习(也希望是为了声誉!)。我希望我能有更多的时间去玩ioctl(感谢 Sneetsher 的建议)以及我迄今为止所做的一切,以便做出更优雅的解决方案,但赏金即将到期,我不太可能及时完成所有工作,所以我“按原样”发布了这个解决方案(至少目前如此)。

免责声明:

我不知道将某些东西改变成什么后果/proc/device-tree,所以如果你真的知道自己在做什么,请继续阅读。

此解决方案的特定实现需要运行内核 > 3.10。它涉及自定义内核模块的编译和脚本的执行,以在和 自定义文件bash之间执行某种热切换。/proc/device-treedevice-tree_new

限制

  1. 删除模块后,自定义/proc/device-tree也被删除!再次阅读免责声明的另一个原因
  2. 自定义/proc/device-tree的缓冲区有字符限制65535。超过该65535字符的所有内容都将被截断。要调整缓冲区的大小,请更改模块源代码中的以下常量定义和变量声明:

    1. #define MAX_BUFFER_SIZE 65535
    2. static unsigned int proc_buffer_length_v;(以便它可以容纳一个数字> 65535

怎么运行的:

模块本身:

  • 删除 /proc/device-tree
  • 创建/proc/device-tree具有权限的新空白0666

脚本bash本身:

  1. 加载模块
  2. 写入/proc/device-tree内容device-tree_new

这是模块的“ Makefile” (Makefile请注意,每行开头的所有空格都make必须替换为TAB字符):

obj-m += proc_module.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

这是proc_module.c该模块的“ ”源文件:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#define DEBUG 1
#define MAX_BUFFER_SIZE 65535

static struct proc_dir_entry* proc_dir_entry_p;
static struct file_operations file_operations_s;
static char* proc_buffer_p;
static unsigned int proc_buffer_length_v;
static unsigned short int read_flag;

int read_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
    if(DEBUG) printk(KERN_INFO "read_proc() called.\n");
    if(read_flag)
        read_flag = 0;
    else {
        read_flag = 1;
        return 0;
    }
    copy_to_user(buffer, proc_buffer_p, proc_buffer_length_v);
    if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
    return proc_buffer_length_v;
}

int write_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
    size_t n;
    if(DEBUG) printk(KERN_INFO "write_proc() called.\n");
    if(count >= MAX_BUFFER_SIZE) {
        if(DEBUG) printk(KERN_INFO "write_proc(): Buffer exceeded!\n");
        n = MAX_BUFFER_SIZE;
    }
    else
        n = count;
    kfree(proc_buffer_p);
    if(DEBUG) printk(KERN_INFO "kfree() called.\n");
    if(!(proc_buffer_p = (char*)kmalloc(MAX_BUFFER_SIZE*sizeof(char), GFP_KERNEL))) {
        if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
        return count;
    }
    if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
    copy_from_user(proc_buffer_p, buffer, n);
    proc_buffer_length_v = n;
    if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
    return count;
}

static int __init init_f(void) {
    if(DEBUG) printk(KERN_INFO "Module inserted.\n");
    remove_proc_entry("device-tree", NULL);
    if(!(proc_dir_entry_p = proc_create("device-tree", 0666, NULL, &file_operations_s))) {
        if(DEBUG) printk(KERN_INFO "Proc entry not created.\n");
        return -1;
    }
    if(DEBUG) printk(KERN_INFO "Proc entry created.\n");
    file_operations_s.read = read_proc;
    file_operations_s.write = write_proc;
    if(!(proc_buffer_p = (char*)kmalloc(1*sizeof(char), GFP_KERNEL))) {
        if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
        return -1;
    }
    if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
    proc_buffer_p[0] = '\0';
    proc_buffer_length_v = 0;
    read_flag = 1;
    if(DEBUG) printk(KERN_INFO "Ok.\n");
    return 0;
}

static void __exit exit_f(void) {
    kfree(proc_buffer_p);
    if(DEBUG) printk(KERN_INFO "kfree() called.\n");
    proc_remove(proc_dir_entry_p);
    if(DEBUG) printk(KERN_INFO "Proc entry removal requested.\n");
    if(DEBUG) printk(KERN_INFO "Module removed.\n");
}

module_init(init_f);
module_exit(exit_f);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kos");
MODULE_DESCRIPTION("proc_module");

这是“ switch.shbash脚本:

#!/bin/bash

sudo rmmod proc_module.ko
sudo insmod proc_module.ko && cat device-tree_new > /proc/device-tree

指示:

  1. Terminal使用Ctrl++打开Altt
  2. 新建一个文件夹:mkdir <folder_name>
  3. 将当前工作目录更改为新文件夹:cd <folder_name>
  4. 使用双引号括起来的完全相同的名称创建上述三个文件
  5. 创建自定义device-tree文件并命名device-tree_new
  6. 将“ switch.sh”标记为可执行:chmod a+x switch.sh
  7. 编译模块:(make将引发两个警告gcc
  8. 启动bash脚本:./switch.sh
  9. cat /proc/device-tree查看结果

答案2

/proc/是一个伪文件系统:当您读取/写入任何文件时,/proc/file您不会访问实际文件或实际内存,而是调用一些充当文件的特定内核函数(取决于文件)。如果您读取文件,它会返回数据;如果您写入文件,它会设置数据。如果没有为特定文件定义写入函数,则写入文件不会改变任何内容。

在这种情况下,/proc/device-tree有一种方法可以在启动时读取正在运行的内核所提供的设备树。(无写入启用)

此外,目前,设备树是只读配置,您无法在启动后更新它。对于您的具体情况,配置您的值i2c是在探测(“安装”)时读取和使用的i2c。如果您想重新配置,您需要像 joshumax 所说的那样,在设备上i2c使用正确的(其中定义了一些特定的“驱动程序条目”)ioctli2c/dev/

另一个解决方案是构建一个新的设备树,I2C根据需要配置设备。然后让内核(检查您正在使用的引导程序)使用您刚刚编译的设备树。

答案3

您需要 root 权限并使用 sudo 来实现这一点。尝试一下:您可以使用以 root 身份运行的 gdb(GNU 调试器)来操作内存内容。以下这些可能会让您感兴趣:

http://sourceware.org/gdb/current/onlinedocs/gdb/

https://stackoverflow.com/questions/3305164/how-to-modify-memory-contents-using-gdb

相关内容