linux device-driver issues

25
Linux device-driver issues

Upload: mallory-daniels

Post on 30-Dec-2015

61 views

Category:

Documents


0 download

DESCRIPTION

Linux device-driver issues. 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. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Linux device-driver issues

Linux device-driver issues

Page 2: Linux device-driver issues

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

Page 3: Linux device-driver issues

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

Page 4: Linux device-driver issues

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 );

}

Page 5: Linux device-driver issues

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 0..255

• Certain of these values are ‘reserved’

Page 6: Linux device-driver issues

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

Page 7: Linux device-driver issues

‘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

Page 8: Linux device-driver issues

‘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

Page 9: Linux device-driver issues

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’

Page 10: Linux device-driver issues

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’) tellskernel to pick an unused major-number

Page 11: Linux device-driver issues

‘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 havingmajor-number=15 and minor-number=0

Page 12: Linux device-driver issues

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?

Page 13: Linux device-driver issues

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

Page 14: Linux device-driver issues

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’?

Page 15: Linux device-driver issues

Kernel System Calls

• Kernel function is named ‘sys_mknod’

• In kernel 2.4.20 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

Page 16: Linux device-driver issues

‘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?

Page 17: Linux device-driver issues

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’

Page 18: Linux device-driver issues

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];

Page 19: Linux device-driver issues

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 0xC0000000

Page 20: Linux device-driver issues

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>

Page 21: Linux device-driver issues

‘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 );

Page 22: Linux device-driver issues

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()

Page 23: Linux device-driver issues

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 );

Page 24: Linux device-driver issues

‘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)

Page 25: Linux device-driver issues

Now: an in-class exercise

• See online version of our ‘stash.c’ driver

• Accessible on our class webpage

• http://nexus.cs.usfca.edu/~cruse/cs635/

• It was written and tested for kernel 2.4.18

• That kernel exported system-call functions

• ‘sys_call_table[]’ lookups weren’t needed

• Can you modify ‘stash.c’ for 2.4.20?