我正在尝试编辑/proc/devices
-tree 内的一个文件,但我无法这样做,我得到:
“权限被拒绝”或“输入/输出错误”。
我尝试了所有可能的编辑器组合chown
,chmod
甚至sudo dd
。我还知道要以十六进制写入的确切内存位置7000c400
。我需要替换那里的 4 个字节,有什么方法可以帮助我实现这一点吗?
编辑:我尝试这样做想要达到什么目的?
我有一个Jetson-TK1董事会和i2c总线设置为默认的
400kHz
,但我想以 运行它100kHz
。我想我可以通过更改设备树结构并重新编译来实现这一点,但重新编译是一个更大的麻烦,因为我使用的内核不是标准内核(nvidia 不提供标准内核)。我曾在某处读到,在 Linux 中几乎所有东西都是文件形式。因此,我查找了一番,找到了一个包含 4 个字节的文件,其值为
400000
,我认为更改此文件会改变频率。现在真正的问题是我无法改变它(我认为我是一个足够优秀的用户,据我所知,如果内存中有东西并且我有各种密码,我应该能够更改它。我搞砸了某件事这一事实不是问题)。我尝试了所有我知道的可能方法(正如我在问题中添加的那样)。那么我该怎么做呢?
答案1
我研究这个问题主要是为了好玩和学习(也希望是为了声誉!)。我希望我能有更多的时间去玩ioctl
(感谢 Sneetsher 的建议)以及我迄今为止所做的一切,以便做出更优雅的解决方案,但赏金即将到期,我不太可能及时完成所有工作,所以我“按原样”发布了这个解决方案(至少目前如此)。
免责声明:
我不知道将某些东西改变成什么后果/proc/device-tree
,所以如果你真的知道自己在做什么,请继续阅读。
此解决方案的特定实现需要运行内核 > 3.10。它涉及自定义内核模块的编译和脚本的执行,以在和 自定义文件bash
之间执行某种热切换。/proc/device-tree
device-tree_new
限制:
- 删除模块后,自定义
/proc/device-tree
也被删除!再次阅读免责声明的另一个原因。 自定义
/proc/device-tree
的缓冲区有字符限制65535
。超过该65535
字符的所有内容都将被截断。要调整缓冲区的大小,请更改模块源代码中的以下常量定义和变量声明:#define MAX_BUFFER_SIZE 65535
static unsigned int proc_buffer_length_v;
(以便它可以容纳一个数字>65535
)
怎么运行的:
模块本身:
- 删除
/proc/device-tree
- 创建
/proc/device-tree
具有权限的新空白0666
脚本bash
本身:
- 加载模块
- 写入
/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.sh
”bash
脚本:
#!/bin/bash
sudo rmmod proc_module.ko
sudo insmod proc_module.ko && cat device-tree_new > /proc/device-tree
指示:
Terminal
使用Ctrl++打开Altt- 新建一个文件夹:
mkdir <folder_name>
- 将当前工作目录更改为新文件夹:
cd <folder_name>
- 使用双引号括起来的完全相同的名称创建上述三个文件
- 创建自定义
device-tree
文件并命名device-tree_new
- 将“
switch.sh
”标记为可执行:chmod a+x switch.sh
- 编译模块:(
make
将引发两个警告gcc
) - 启动
bash
脚本:./switch.sh
cat /proc/device-tree
查看结果
答案2
/proc/
是一个伪文件系统:当您读取/写入任何文件时,/proc/file
您不会访问实际文件或实际内存,而是调用一些充当文件的特定内核函数(取决于文件)。如果您读取文件,它会返回数据;如果您写入文件,它会设置数据。如果没有为特定文件定义写入函数,则写入文件不会改变任何内容。
在这种情况下,/proc/device-tree
有一种方法可以在启动时读取正在运行的内核所提供的设备树。(无写入启用)
此外,目前,设备树是只读配置,您无法在启动后更新它。对于您的具体情况,配置您的值i2c
是在探测(“安装”)时读取和使用的i2c
。如果您想重新配置,您需要像 joshumax 所说的那样,在设备上i2c
使用正确的(其中定义了一些特定的“驱动程序条目”)ioctl
i2c
/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