how to access kernel driver from user-space
TRANSCRIPT
How to Access Kernel Driver from User-
spaceSheng-Wei, Lin
2015/03/26
Introduction Character Device Input/Output Control Input Device Device Attributes in Sysfs
Outline
Introduction
Architecture of GNU/Linux OS
Character device◦ Accessed as a stream of bytes by means of
filesystem nodes under /dev, such as tty, serial devices.
Device driver – Character Device
Char devcies Major number Minor number
Roles of Major/Minor Number
/dev/devicen
Process
kobj_map
char driver
physical device
user space
kernel space
open()
sys_open()
Major number used to match the corresponding driver
Minor number used to identify devices
struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
};
Structure of Character Device
struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *filp, char __user *buf, size_t count, loff_t *ppos);ssize_t (*write) (struct file *filp, const char __user *buf, size_t count, loff_t *ppos);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);
…………………………………….};
File Operations
#include <asm/uaccess.h> /* Copy data from user space to kernel space. */ unsigned long copy_from_user (void *to, const void *from,
unsigned long count) /* Copy a block of data into user space. */ unsigned long copy_to_user(void *to, const void *from,
unsigned long count) /* Write a simple value into user space. */ int put_user(x, ptr) , __put_user(x, ptr) /* Get a simple variable from user space. */ int get_user(x, ptr), __get_user(x, ptr)
Data Copy between Kernel-space & User-space
Process Virtual Space
#include <asm/uaccess.h> /* Copy data from user space to kernel space. */ unsigned long copy_from_user (void *to, const void *from,
unsigned long count) /* Copy a block of data into user space. */ unsigned long copy_to_user(void *to, const void *from,
unsigned long count) /* Write a simple value into user space. */ int put_user(x, ptr) , __put_user(x, ptr) /* Get a simple variable from user space. */ int get_user(x, ptr), __get_user(x, ptr)
Data Copy between Kernel-space & User-space
Process Virtual Space
without access_ok() check
Flow of Data Read
0xC0000000
0xFFFFFFFF
0x00000000
1GB
3GB
datacdev->ops->read()
read()
sys_read()kernel space
user spaceProcess Virtual
Space
Flow of Data Read
0xC0000000
0xFFFFFFFF
0x00000000
1GB
3GB data
datacdev->ops->read()
read()
sys_read()
copy_to_user()
Process Virtual Space
kernel space
user space
#include <linux/cdev.h>#include <linux/types.h>#include <linux/device.h>
/* register a range of char device numbers */ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char
*name) /* initialize a cdev structure */ void cdev_init(struct cdev *cdev, const struct file_operations *fops) /* add a char device to the system */ int cdev_add(struct cdev *p, dev_t dev, unsigned count) /* create a struct class structure */ int class_create(struct module *owner, const char *name) /* creates a device and registers it with sysfs */ struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
Registration of Character Device
IOCTL◦ A system call that offers a way to access device-
specific commands
Input/Output Control (IOCTL)
ioctl(int fd, int cmd, …)
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
User-space
Kernel-space
struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);
…………………………………….};
File Operations
Command format
android/kernel/Documentation/ioctl/ioctl-number.txt Macros for command setup /* An ioctl with no parameters */
◦ IO(type, nr) /* An ioctl with read parameters (copy_to_user) */
◦ _IOR(type, nr, datatype) /* An ioctl with write parameters (copy_from_user) */
◦ _IOW(type, nr,datatype) /* An ioctl with both write and read parameters */
◦ _IOWR(type, nr, datatype)
IOCTL Command
dir size type nr
MSB LSB
2 bit 14 bit 8 bit 8bit
An event-driven device that reports input events to user applications through character devices in the /dev/input directory◦ E.g., button, mouse, joystick.
Device driver – Input Device
Input Subsystem
input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
android/kernel/Documentation/input/event-codes.txt EV_KEY:
◦ Used to describe state changes of keyboards, buttons, etc.◦ e.g., KEY_POWER, KEY_VOLUMEUP, KEY_VOLUMEDOWN
EV_ABS:◦ Used to describe absolute axis value changes◦ e.g., ABS_X, ABS_Y, ABS_Z
EV_REL:◦ Used to describe relative axis value changes◦ e.g., REL_X, REL_Y, REL_Z
z
Event Types & Codes
Sysfs◦ A virtual filesystem that contains information
about device, drivers and buses as seen from the kernel.
Device attribute◦ Exported for kobjects in the form of regular files in
sysfs. Sysfs forwards file I/O operations to methods defined for the attributes, providing a means to read and write kernel attributes.
Device Attributes in Sysfs
#include <linux/device.h>
/* Declare a device attribute */ DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)/* Store attributes into array */ static struct attribute * attrs[] = {…};/* Declare a attribute group */ struct attribute_group { const char *name; umode_t (*is_visible)(struct kobject *, struct attribute *, int); struct attribute **attrs;};/* Given a directory kobject, create an attribute group */ int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);
Device Attributes Setup
What does the file operation should be used if we want to enable a serial character device ?
Q1
What does the file operation should be used if we want to enable a serial character device ?
-> IOCTL
Q1
How does the kernel identify the corresponding
driver when opening /dev/tty0 ?
Q2
How does the kernel identify the corresponding
driver when opening /dev/tty0 ?-> Major number
Q2
/dev/devicen
Process
kobj_map
device driver
physical device
user space
kernel space
open()
sys_open()Major number used to match the corresponding driver
Minor number used to identify devices