Read data from EEPROM in Linux kernel module - linux-kernel

I have to read MAC address from EEPROM and set it to the network interface while the interface is initializing.And I followed the comment from Read EEPROM entry from linux module to read EEPROM through sysfs. But the result is failed.
When I opened the EEPROM file through filp_open(), it always return error pointer with -EACCESS.
struct file *kernel_open(const char *filename, int flags, umode_t mode) {
struct file *filp = NULL;
mm_segment_t oldfs = get_fs();
set_fs(get_ds());
filp = filp_open(filename, flags, mode);
set_fs(oldfs);
return filp;
}
const char *filename = "/sys/bus/i2c/devices/6-0054/eeprom";
struct file filp = kernel_open(filename, O_RDONLY, 0);
if (IS_ERR(filp)) {
printk(KERN_ERR "Failed to open file (code: %d)\n", PTR_ERR(filp));
return; <-- always return here and filp value with -13, aka -EACCESS, aka Permission denied
}
Have any ideas?
[Updated]- Processor: AST2500 (ARMv6)- Kernel version: 4.19- EEPROM: at24c64

Related

How to trigger fops poll function from the kernel driver

I am working on a kernel driver which logs some spi data in a virtual file using debugfs.
My main goal is to be able to "listen" for incomming data from userspace using for example $ tail -f /sys/kernel/debug/spi-logs which is using select to wait for new data on the debugfs file.
I've implemented the fops poll function in the driver and when I am trying to get the data from the userspace, the poll function is never called even though there is new data available in the kernel to be read.
I assume that the poll function never gets called because the debugfs file never gets actually written.
My question is, is there a way to trigger the poll function from the kernel space when new data is available?
EDIT: Added an example
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/poll.h>
struct module_ctx {
struct wait_queue_head wq;
};
struct module_ctx module_ctx;
static ssize_t debugfs_read(struct file *filp, char __user *buff, size_t count, loff_t *off)
{
// simulate no data left to read for now
return 0;
}
static __poll_t debugfs_poll(struct file *filp, struct poll_table_struct *wait) {
struct module_ctx *module_hdl;
__poll_t mask = 0;
module_hdl = filp->f_path.dentry->d_inode->i_private;
pr_info("CALLED!!!");
poll_wait(filp, &module_hdl->wq, wait);
if (is_data_available_from_an_external_ring_buffer())
mask |= POLLIN | POLLRDNORM;
return mask;
}
loff_t debugfs_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t pos = filp->f_pos;
switch (orig) {
case SEEK_SET:
pos = offset;
break;
case SEEK_CUR:
pos += offset;
break;
case SEEK_END:
pos = 0; /* Going to the end => to the beginning */
break;
default:
return -EINVAL;
}
filp->f_pos = pos;
return pos;
}
static const struct file_operations debugfs_fops = {
.owner = THIS_MODULE,
.read = debugfs_read,
.poll = debugfs_poll,
.llseek = debugfs_llseek,
};
static int __init rb_example_init(void)
{
struct dentry *file;
init_waitqueue_head(&module_ctx.wq);
file = debugfs_create_file("spi_logs", 0666, NULL, &module_ctx,
&debugfs_fops);
if (!file) {
pr_err("qm35: failed to create /sys/kernel/debug/spi_logs\n");
return 1;
}
return 0;
}
static void __exit
rb_example_exit(void) {
}
module_init(rb_example_init);
module_exit(rb_example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mihai Pop");
MODULE_DESCRIPTION("A simple example Linux module.");
MODULE_VERSION("0.01");
Using tail -f /sys/kernel/debug/spi_logs, the poll function never gets called
Semantic of poll is to return whenever encoded operations (read and/or write) on a file would return without block. In case of read operation, "block" means:
If read is called in nonblocking mode (field f_flags of the struct file has flag O_NONBLOCK set), then it returns -EAGAIN.
If read is called in blocking mode, then it puts a thread into the waiting state.
As you can see, your read function doesn't follow that convention and returns 0, which means EOF. So the caller has no reason to call poll after that.
Semantic of -f option for tail:
... not stop when end of file is reached, but rather to wait ...
is about the situation, when read returns 0, but the program needs to wait.
As you can see, poll semantic is not suitable for such wait. Instead, such programs use inotify mechanism.

Cannot printk user space string parameter when intercepting a syscall

I'm trying to intercept a Linux syscall to record all opened filename to a log file. but there's a problem: it failed to printk the filename in user space. Here are the codes of fake syscall function:
static inline long hacked_open(const char __user *filename, int flags, umode_t mode)
{
char buf[256];
buf[255] = '\0';
long res = strncpy_from_user(buf, filename, 255);
if (res > 0)
printk("%s\n", buf);
else
printk("---err len : %ld ---\n", res);
orig_func a = (orig_func)orig_open;
return a(filename, flags, mode);
}
after I loaded the kernel module, dmesg showed a lot of message as:
---err len : -14---
I've tried copy_from_user and printk the filename directly, but they all doesn't work.
I've solved this problem by myself.
the parameters of hacked_open are wrong.
the correct hacked_openat should be :
asmlinkage long hacked_openat(struct pt_regs *regs)
and we can get filename from user-space like this:
int nRet = strncpy_from_user(filename, (char __user *)regs->si, 1024);

Registering Platform Device with info from Device Tree

I am using Petalinux for a Xilinx Zynq application, and I am new to kernel driver development.
I created a kernel module for a platform driver for an AXI FIFO interface. The devices seems to be recognised from the device tree using the .of_match_table, since I can see the correct memory space reserved with cat /proc/iomem .
If I search for the driver name xxx I get
./lib/modules/4.4.0-xilinx/extra/xxx.ko
./sys/bus/platform/drivers/xxx
./sys/module/xxx
./sys/module/xxx/drivers/platform:xxx
I found the device under /sys/bus/platform/devices/43c00000.axi_xxxx but still can't access it or see it under /dev/.
How do I register device so that I can open it from my user space app?.
Do I need to allocate memory for it and then register a new device using platform_device_register(pdev)?
Thanks
You need to register your device in a framework to get a device file created.
I would suggest registering a miscdevice in your case. It simply registers a character device.
static struct miscdevice miscdev;
static ssize_t myaxi_read(struct file *file, char __user *buf,
size_t sz, loff_t *ppos)
{
// Do something
}
static ssize_t myaxi_write(struct file *file, const char __user *buf,
size_t sz, loff_t *ppos)
{
// Do something
}
static const struct file_operations myaxi_fops = {
.owner = THIS_MODULE,
.write = myaxi_write,
.read = myaxi_read,
};
In your probe:
miscdev.minor = MISC_DYNAMIC_MINOR;
miscdev.name = "myaxi";
miscdev.fops = &myaxi_fops;
misc_register(&miscdev);
You can read more about linux kernel driver development and the device model at http://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf

How to dump/list all kernel symbols with addresses from Linux kernel module?

In a kernel module, how to list all the kernel symbols with their addresses?
The kernel should not be re-compiled.
I know "cat /proc/kallsyms" in an interface, but how to get them directly from kernel data structures, using functions like kallsyms_lookup_name.
Example
Working module code:
#include <linux/module.h>
#include <linux/kallsyms.h>
static int prsyms_print_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
pr_info("### %lx\t%s\n", address, namebuf);
return 0;
}
static int __init prsyms_init(void)
{
kallsyms_on_each_symbol(prsyms_print_symbol, NULL);
return 0;
}
static void __exit prsyms_exit(void)
{
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
Explanation
kernel/kallsyms.c implements /proc/kallsyms. Some of its functions are available for external usage. They are exported via EXPORT_SYMBOL_GPL() macro. Yes, your module should have GPL license to use it. Those functions are:
kallsyms_lookup_name()
kallsyms_on_each_symbol()
sprint_symbol()
sprint_symbol_no_offset()
To use those functions, include <linux/kallsyms.h> in your module. It should be mentioned that CONFIG_KALLSYMS must be enabled (=y) in your kernel configuration.
To print all the symbols you obviously have to use kallsyms_on_each_symbol() function. The documentation says next about it:
/* Call a function on each kallsyms symbol in the core kernel */
int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
unsigned long), void *data);
where fn is your callback function that should be called for each symbol found, and data is a pointer to some private data of yours (will be passed as first parameter to your callback function).
Callback function must have next signature:
int fn(void *data, const char *namebuf, struct module *module,
unsigned long address);
This function will be called for each kernel symbol with next parameters:
data: will contain pointer to your private data you passed as last argument to kallsyms_on_each_symbol()
namebuf: will contain name of current kernel symbol
module: will always be NULL, just ignore that
address: will contain address of current kernel symbol
Return value should always be 0 (on non-zero return value the iteration through symbols will be interrupted).
Supplemental
Answering the questions in your comment.
Also, is there a way to output the size of each function?
Yes, you can use sprint_symbol() function I mentioned above to do that. It will print symbol information in next format:
symbol_name+offset/size [module_name]
Example:
psmouse_poll+0x0/0x30 [psmouse]
Module name part can be omitted if symbol is built-in.
I tried the module and see the result with "dmesg". But a lot of symbols are missing such as "futex_requeue". The output symbol number is about 10K, while it is 100K when I use "nm vmlinux".
This is most likely because your printk buffer size is insufficient to store all the output of module above.
Let's improve above module a bit, so it provides symbols information via miscdevice. Also let's add function size to the output, as requested. The code as follows:
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/sizes.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#define DEVICE_NAME "prsyms2"
/* 16 MiB is sufficient to store information about approx. 200K symbols */
#define SYMBOLS_BUF_SIZE SZ_16M
struct symbols {
char *buf;
size_t pos;
};
static struct symbols symbols;
/* ---- misc char device definitions ---- */
static ssize_t prsyms2_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
return simple_read_from_buffer(buf, count, pos, symbols.buf,
symbols.pos);
}
static const struct file_operations prsyms2_fops = {
.owner = THIS_MODULE,
.read = prsyms2_read,
};
static struct miscdevice prsyms2_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &prsyms2_fops,
};
/* ---- module init/exit definitions ---- */
static int prsyms2_store_symbol(void *data, const char *namebuf,
struct module *module, unsigned long address)
{
struct symbols *s = data;
int count;
/* Append address of current symbol */
count = sprintf(s->buf + s->pos, "%lx\t", address);
s->pos += count;
/* Append name, offset, size and module name of current symbol */
count = sprint_symbol(s->buf + s->pos, address);
s->pos += count;
s->buf[s->pos++] = '\n';
if (s->pos >= SYMBOLS_BUF_SIZE)
return -ENOMEM;
return 0;
}
static int __init prsyms2_init(void)
{
int ret;
ret = misc_register(&prsyms2_misc);
if (ret)
return ret;
symbols.pos = 0;
symbols.buf = vmalloc(SYMBOLS_BUF_SIZE);
if (symbols.buf == NULL) {
ret = -ENOMEM;
goto err1;
}
dev_info(prsyms2_misc.this_device, "Populating symbols buffer...\n");
ret = kallsyms_on_each_symbol(prsyms2_store_symbol, &symbols);
if (ret != 0) {
ret = -EINVAL;
goto err2;
}
symbols.buf[symbols.pos] = '\0';
dev_info(prsyms2_misc.this_device, "Symbols buffer is ready!\n");
return 0;
err2:
vfree(symbols.buf);
err1:
misc_deregister(&prsyms2_misc);
return ret;
}
static void __exit prsyms2_exit(void)
{
vfree(symbols.buf);
misc_deregister(&prsyms2_misc);
}
module_init(prsyms2_init);
module_exit(prsyms2_exit);
MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Module for printing all kernel symbols");
MODULE_LICENSE("GPL");
And here is how to use it:
$ sudo insmod prsyms2.ko
$ sudo cat /dev/prsyms2 >symbols.txt
$ wc -l symbols.txt
$ sudo rmmod prsyms2
File symbols.txt will contain all kernel symbols (both built-in and from loaded modules) in next format:
ffffffffc01dc0d0 psmouse_poll+0x0/0x30 [psmouse]
It seems that I can use kallsyms_lookup_name() to find the address of the function, can then use a function pointer to call the function?
Yes, you can. If I recall correctly, it's called reflection. Below is an example how to do so:
typedef int (*custom_print)(const char *fmt, ...);
custom_print my_print;
my_print = (custom_print)kallsyms_lookup_name("printk");
if (my_print == 0) {
pr_err("Unable to find printk\n");
return -EINVAL;
}
my_print(KERN_INFO "### printk found!\n");

Using an old device file for char device driver

I have two questions as I'm trying device drivers as a beginner.
I created one module , loaded it, it dynamically took major number 251 say. Number of minor devices is kept 1 only i.e minor number 0. For testing , I tried echo and cat on the device file (created using mknod) and it works as expected. Now if I unload the module but don't remove /dev entry and again load the module with same major number and try writing/reading to same device file which was used previously, kernel crashes. I know we shouldn't do this but just want to understand what happens in this scenario which causes this crash. I think something that VFS does.
When I do cat on device file, the read keeps on happening indefinitely. why? To stop that needed to use offset manipulation. This looks to be because buffer length is coming as 32768 as default to read?
EDIT: further in this I added one ioctl function as below, then I'm getting error regarding the storage class of init and cleanup function, which work well if no ioctl is defined. Not getting the link between ioctl and the init/cleanup functions' storage class. Updated code is posted. Errors are below:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function]
Below is the code:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#define SUCCESS 0
#define BUF_LEN 80
#define FLOWTEST_MAGIC 'f'
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int)
MODULE_LICENSE("GPL");
int minor_num=0,i;
int num_devices=1;
int fopen=0,counter=0,ioctl_test;
static struct cdev ms_flow_cd;
static char c;
///// Open , close and rest of the things
static int flow_open(struct inode *f_inode, struct file *f_file)
{
printk(KERN_ALERT "flowtest device: OPEN\n");
return SUCCESS;
}
static ssize_t flow_read(struct file *f_file, char __user *buf, size_t
len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off);
/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */
if(*off==1)
return 0;
printk(KERN_INFO "Copying...\n");
copy_to_user(buf,&c,1);
printk(KERN_INFO "Copied : %s\n",buf);
*off = *off+1;
return 1; // Return 1 on first read
}
static ssize_t flow_write(struct file *f_file, const char __user *buf,
size_t len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: WRITE()\n");
if (copy_from_user(&c,buf+len-2,1) != 0)
return -EFAULT;
else
{
printk(KERN_INFO "Length len = %d\n\nLast character written is - %c\n",len,*(buf+len-2));
return len;
}
}
static int flow_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "ms_tty Device: CLOSE()\n");
return 0;
}
///* ioctl commands *///
static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case FLOW_QUERY:
ioctl_test=51;
return ioctl_test;
default:
return -ENOTTY;
}
///////////////////File operations structure below/////////////////////////
struct file_operations flow_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = flow_read,
.write = flow_write,
.unlocked_ioctl = flow_ioctl,
.open = flow_open,
.release = flow_close
};
static int flow_init(void)
{
printk(KERN_ALERT "Here with flowTest module ... loading...\n");
int result=0;
dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num,
num_devices,"mod_flowtest"); // allocate major number dynamically.
i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);
cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);
return 0;
}
static void flow_terminate(void)
{
dev_t devno=MKDEV(i,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
printk(KERN_ALERT "Going out... exiting...\n");
unregister_chrdev_region(devno,num_devices); //remove entry from the /proc/devices
}
module_init(flow_init);
module_exit(flow_terminate);
1- You're missing cdev_del() in your cleanup function. Which means the device stays registered, but the functions to handle it are unloaded, thus the crash. Also, cdev_add probably fails on the next load, but you don't know because you're not checking return values.
2- It looks ok... you modify offset, return the correct number of bytes, and then return 0 if offset is 1, which indicates EOF. But you should really check for *off >= 1.
EDIT-
The length passed into your read handler function comes all the way from user-land read(). If the user opens the device file and calls read(fd, buf, 32768);, that just means the user wants to read up to 32768 bytes of data. That length gets passed all the way to your read handler. If you don't have 32768 bytes of data to supply, you supply what you have, and return the length. Now, the user code isn't sure if that's the end of the file or not, so it tries for another 32768 read. You really have no data now, so you return 0, which tells the user code that it has hit EOF, so it stops.
In summary, what you're seeing as some sort of default value at the read handler is just the block size that the utility cat uses to read anything. If you want to see a different number show up at your read function, try using dd instead, since it lets you specify the block size.
dd if=/dev/flowtest of=/dev/null bs=512 count=1
In addition, this should read one block and stop, since you're specifying count=1. If you omit count=1, it will look more like cat, and try to read until EOF.
For 2, make sure you start your module as a char device when using mknod.
mknod /dev/you_device c major_number minor_number

Resources