Download presentation
Presentation is loading. Please wait.
1
Linux device-driver issues
2
Devices as ‘special’ files
Unix programs treat most devices as files Provides a familiar programming interface Standard C functions: open(), read(), etc But such devices need to have ‘filenames’ Device files are located in ‘/dev’ directory
3
Example: our ‘led’ device
We created a ‘char’ device-driver: ‘led.c’ It operated a standard keyboard’s LEDs It was a ‘write-only’ character device Applications saw it as a file: ‘/dev/led’ We tested it using: $ echo 7 > /dev/led That command ‘turned on’ all three LEDs
4
Example C++ application
int main( void ) { int fd = open( “/dev/led”, O_WRONLY ); if ( fd < 0 ) { perror( “open” ); exit(1); } char indicator = 7; write( fd, &indicator, 1 ); close( fd ); }
5
Kernel uses different ID-scheme
Kernel uses number-pairs (major,minor) The ‘major’ number identifies the driver The ‘minor’ number identifies the device One driver can control multiple devices Range for ‘major’ numbers is Certain of these values are ‘reserved’
6
Assigning ‘major’ numbers
Driver-author can select a major number Kernel is told during driver ‘registration’ But author must be careful: no duplication! Registration fails if number already used View currently used major numbers with $ cat /proc/devices
7
‘Dynamic’ module loading
Linux lets module be loaded ‘on demand’ This could cause ‘contention’ for numbers Example: your driver uses major=6 But line-printer driver (‘lp.c’) uses major=6 During printing your module won’t install And printing fails if your module is installed
8
‘Official’ device-numbers
There is a ‘registry’ of device-numbers See file ‘devices.txt’ in kernel sources Look in: /usr/src/linux/Documentation Maintaining this registry is a ‘big hassle’ (e.g., delays, arguments, too few numbers) So some alternative solution was needed
9
Dynamic assignment Module author can let kernel choose major
This is why major-number 0 is never used If programmer requests major-number 0, kernel assigns an available major-number Kernel informs driver during ‘registration’
10
Driver registration int register_chrdev( unsigned int major,
const char *driver_name, struct file_operations *fops ); Returns: major-number (or error-code) Using 0 as first argument (‘major’) tells kernel to pick an unused major-number
11
‘Chicken-and-Egg’ problem?
A driver’s device-file(s) must be created Creator must know device major-number (Also creator will need ‘root’ privileges!) Example: root# mknod /dev/led c 15 0 Creates a character device-node having major-number=15 and minor-number=0
12
Obstacles for us How to we find out what major-number the kernel dynamically assigned to our driver? How can we create special files in ‘/dev’ that allow applications to use our driver? How to we set the ‘file permissions’ so a normal program can open, read/write to our devices?
13
Overcoming those obstacles
Our driver will know its major-number ‘init_module()’ will ‘register’ our driver Return-value will be the major-number We could use ‘printk()’ to display its value Then a user could create the device-file BUT: will the user be allowed to do it? ‘mknod’ and ‘chmod’ need root privileges
14
One convenient solution
Let our module setup its own device-file(s) Our module will know the major-number and our module has ‘root’ privileges BUT Can modules execute ‘mknod’? ‘chmod’?
15
Kernel System Calls Kernel function is named ‘sys_mknod’
In kernel this ‘symbol’ isn’t exported Module loader can’t link our module to it Which kernel symbols ARE exported? Use: $ cat /proc/ksyms Ugh! Hundreds of exported kernel symbols Better: $ grep sys_mknod /proc/ksyms
16
‘sys_call_table’ is exported
Try: $ cat sys_call_table /proc/ksyms We CAN link our with ‘sys_call_table’ Declare: extern void *sys_call_table[]; I.e., ‘sys_call_table’ is an array of pointers A pointer to ‘sys_mknod’ is in this array! But where?
17
Header-file: ‘asm/unistd.h’
Kernel-header defines symbolic constants Examples: #define __NR_mknod 14 #define __NR_chmod 15 These are indexes into ‘sys_call_table’ So function-pointers can be ‘looked up’
18
Programming Syntax Declare static function-pointer variables:
static int (*sys_mknod)( const char *, … ); static int (*sys_chmod)( const char *, … ); Initialize these function-pointer variables: sys_mknod = sys_call_table[ __NR_mknod]; sys_chmod = sys_call_table[ __NR_chmod];
19
One further ‘gotcha’ System-call expect user-space arguments
E.g., filename is a string from user-space Kernel will check for an “illegal’ argument A system-call from kernel-space will fail! PAGE_OFFSET is origin of kernel-space Normally PAGE_OFFSET is 0xC
20
Raising the ‘user-space’ roof
Top of user-space is a task-variable Each task has its own local copy Kept in the ‘struct task_struct’ structure Assigned during task-creation (e.g., fork() ) Kernel can change this variable’s value! Syntax: set_fs( get_ds() ); Needs header: #include <asm/uaccess.h>
21
‘init_module’ algorithm
char nm = “led”; struct file_operations fops = { write: write, }; int major = register_chrdev(0, nm, &fops ); Dev_t dev_id = MKDEV( major, minor ); sys_mknod = sys_call_table[ __NR_mknod]; set_fs( get_ds() ); sys_mknod( “/dev/led”, S_IFCHR, dev_id );
22
How to remove a device-file
Another ‘privileged’ command Example: root# unlink /dev/led We can let our ‘cleanup_module()’ do it But ‘cleanup’ and ‘init’ are different tasks: root# /sbin/insmod led.o root# /sbin/rmmod led ‘insmod’ will call our init_module() ‘rmmod’ will call our cleanup_module()
23
Algorithm for ‘cleanup’
const char modname[] = “led”; unregister_chrdev( major, modname ); sys_unlink = sys_call_table[ __NR_unlink ]; set_fs( get_ds() ); const char devname[] = “/dev/led”; sys_unlink( devname );
24
‘pseudo-code’ versus C
Previous slides showed algorithm-steps BUT C language has special requirement Within each C program-block: all of block’s local variables are declared (and, optionally, initialized) BEFORE any executable-statements appear This differs from C++ (which is less strict)
25
Now: an in-class exercise
See online version of our ‘stash.c’ driver Accessible on our class webpage It was written and tested for kernel That kernel exported system-call functions ‘sys_call_table[]’ lookups weren’t needed Can you modify ‘stash.c’ for ?
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.