Linux内核模块读取EEPROM的MAC地址时遇-EACCESS权限问题求助
解决内核态读取EEPROM(AT24C64)MAC地址时的-EACCESS问题
首先,不推荐在内核态通过sysfs的filp_open()读取EEPROM——sysfs是为用户空间交互设计的接口,内核态直接访问不仅容易遇到权限问题,也不符合内核编程的最佳实践。针对你的场景(AST2500 + 内核4.19 + AT24C64),推荐以下两种解决思路:
思路1:直接通过I2C子系统内核API读取(最优方案)
内核提供了完善的I2C设备操作接口,直接调用这些API访问AT24C64是最可靠的方式:
步骤1:获取目标I2C设备的i2c_client
你可以通过设备树匹配、或者I2C设备ID匹配来获取i2c_client。比如如果内核已经加载了at24驱动(AT24系列EEPROM的通用驱动),可以通过总线和地址查找:
#include <linux/i2c.h> struct i2c_adapter *adapter = i2c_get_adapter(6); // 对应I2C总线6 if (!adapter) { printk(KERN_ERR "Failed to get I2C adapter 6\n"); return; } struct i2c_client *client = i2c_new_device(adapter, &(struct i2c_board_info){ .type = "at24c64", .addr = 0x54, // AT24C64的硬件地址,根据接线调整 }); i2c_put_adapter(adapter); if (!client) { printk(KERN_ERR "Failed to create I2C client for AT24C64\n"); return; }
步骤2:读取EEPROM中的MAC地址
AT24C64是I2C接口的EEPROM,通常MAC地址会被烧录在固定偏移(比如0x00开头的6个字节),可以用i2c_master_send和i2c_master_recv组合读取:
#include <linux/etherdevice.h> unsigned char mac_addr[6]; unsigned char read_offset = 0x00; // MAC地址存储的起始偏移 // 先向EEPROM写入要读取的偏移地址 int ret = i2c_master_send(client, &read_offset, 1); if (ret < 0) { printk(KERN_ERR "Failed to set EEPROM read offset\n"); goto cleanup; } // 读取6字节MAC地址 ret = i2c_master_recv(client, mac_addr, 6); if (ret != 6) { printk(KERN_ERR "Failed to read MAC address, got %d bytes\n", ret); goto cleanup; } // 验证MAC地址有效性 if (!is_valid_ether_addr(mac_addr)) { printk(KERN_WARNING "Invalid MAC address read from EEPROM\n"); } else { // 将MAC地址设置到目标网络接口 ret = dev_set_mac_address(net_dev, NULL, mac_addr); if (ret < 0) { printk(KERN_ERR "Failed to set MAC address to interface\n"); } } cleanup: i2c_unregister_device(client);
思路2:解决sysfs路径的-EACCESS问题(不推荐)
如果因为某些原因必须通过sysfs读取,你需要绕过或解决权限检查:
- 临时提升内核态权限:sysfs文件的权限检查会校验调用者的cred,你可以临时切换到init进程的cred来绕过检查:
struct cred *old_cred; old_cred = override_creds(get_init_cred()); filp = filp_open(filename, O_RDONLY, 0); revert_creds(old_cred); - 检查内核安全机制:如果内核启用了SELinux或SMACK,可能会阻止内核态访问sysfs文件。可以通过内核配置(
CONFIG_SELINUX=n)或者临时关闭SELinux(echo 0 > /sys/fs/selinux/enforce)测试。 - 确认路径正确性:执行
i2cdetect -y 6验证总线6上是否存在0x54地址的设备,同时确认/sys/bus/i2c/devices/6-0054/eeprom文件确实存在且权限为-r--r--r--。
额外提示
- AST2500的I2C控制器可能需要特殊的时钟配置,确保内核I2C驱动已经将总线6的速率设置为AT24C64支持的范围(最高400kHz)。
- 可以参考内核源码
drivers/misc/eeprom/at24.c,了解at24驱动提供的内核态操作接口,避免重复造轮子。
内容的提问来源于stack exchange,提问作者Richard B. Vannacutt




