Character Device Driver � ( Pre req: Multi tasking, threading)
Dr A Sahu
Dept of Comp Sc & Engg.
IIT Guwahati
Outline
Linux Char Vs block
$cd /dev/block/
$ ls –l
rwxrwxrwx 1 root root 7 2010-08-12 21:32 1:0 -> ../ram0
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 1:1 -> ../ram1
…
lrwxrwxrwx 1 root root 8 2010-08-12 21:32 1:15 -> ../ram15
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 11:0 -> ../sr0
lrwxrwxrwx 1 root root 8 2010-08-13 03:02 7:0 -> ../loop0
lrwxrwxrwx 1 root root 8 2010-08-13 03:02 7:1 -> ../loop1
….
rwxrwxrwx 1 root root 8 2010-08-13 03:02 7:7 -> ../loop7
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 8:0 -> ../sda
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 8:1 -> ../sda1
….
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 8:5 -> ../sda5
Mount –o loop CD.iso /mnt/cdrom
# Formats, mounts, and sets permissions on my 16MB ramdisk $/bin/mount /dev/ram0 /mnt/rd
Linux Char Vs block
$cd /dev/char/
$ ls –l
lrwxrwxrwx 1 root root 8 2010-08-13 03:02 10:144 -> ../nvram
lrwxrwxrwx 1 root root 15 2010-08-12 21:32 10:223 -> ../input/uinput
lrwxrwxrwx 1 root root 9 2010-08-13 03:02 10:227 -> ../mcelog
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 10:228 -> ../hpet
lrwxrwxrwx 1 root root 7 2010-08-12 21:33 10:229 -> ../fuse
lrwxrwxrwx 1 root root 11 2010-08-13 03:02 10:231 -> ../snapshot
lrwxrwxrwx 1 root root 6 2010-08-12 21:32 10:232 -> ../kvm
lrwxrwxrwx 1 root root 13 2010-08-12 21:32 10:57 -> ../vboxnetctl
lrwxrwxrwx 1 root root 10 2010-08-12 21:32 10:58 -> ../vboxdrv
lrwxrwxrwx 1 root root 21 2010-08-13 03:02 10:59 -> ../network_throughput
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 10:60 -> ../network_latency
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 10:61 -> ../cpu_dma_latency
lrwxrwxrwx 1 root root 17 2010-08-13 03:02 10:62 -> ../mapper/control
lrwxrwxrwx 1 root root 14 2010-08-13 03:02 10:63 -> ../vga_arbiter
Linux Char Vs block
$cd /dev/char/
$ ls –l
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 1:1 -> ../mem
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 1:11 -> ../kmsg
lrwxrwxrwx 1 root root 9 2010-08-13 03:02 1:12 -> ../oldmem
lrwxrwxrwx 1 root root 15 2010-10-06 22:42 116:10 -> ../snd/pcmC1D0c
lrwxrwxrwx 1 root root 16 2010-10-06 22:42 116:11 -> ../snd/controlC1
lrwxrwxrwx 1 root root 12 2010-08-12 21:32 116:2 -> ../snd/timer
lrwxrwxrwx 1 root root 10 2010-08-12 21:32 116:3 -> ../snd/seq
lrwxrwxrwx 1 root root 15 2010-08-12 21:32 116:4 -> ../snd/pcmC0D1p
lrwxrwxrwx 1 root root 15 2010-08-12 21:32 116:5 -> ../snd/pcmC0D0p
lrwxrwxrwx 1 root root 15 2010-08-12 21:32 116:6 -> ../snd/pcmC0D0c
lrwxrwxrwx 1 root root 13 2010-08-12 21:32 116:7 -> ../snd/hwC0D3
lrwxrwxrwx 1 root root 16 2010-08-12 21:32 116:8 -> ../snd/controlC0
lrwxrwxrwx 1 root root 15 2010-10-06 22:42 116:9 -> ../snd/pcmC1D0p
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 1:3 -> ../null
lrwxrwxrwx 1 root root 15 2010-08-13 03:02 13:32 -> ../input/mouse0
lrwxrwxrwx 1 root root 15 2010-08-13 03:02 13:33 -> ../input/mouse1
lrwxrwxrwx 1 root root 13 2010-08-13 03:02 13:63 -> ../input/mice
Linux Char Vs block
$cd /dev/char/
$ ls –l
lrwxrwxrwx 1 root root 15 2010-08-13 03:02 13:64 -> ../input/event0
lrwxrwxrwx 1 root root 15 2010-08-13 03:02 13:65 -> ../input/event1
lrwxrwxrwx 1 root root 15 2010-08-13 03:02 13:66 -> ../input/event2
rwxrwxrwx 1 root root 13 2010-08-13 03:02 162:0 -> ../raw/rawctl
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 1:7 -> ../full
lrwxrwxrwx 1 root root 9 2010-08-13 03:02 1:8 -> ../random
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:0 -> ../bus/usb/001/001
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:128 -> ../bus/usb/002/001
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:256 -> ../bus/usb/003/001
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:384 -> ../bus/usb/004/001
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:512 -> ../bus/usb/005/001
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:513 -> ../bus/usb/005/002
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:640 -> ../bus/usb/006/001
lrwxrwxrwx 1 root root 18 2010-10-06 22:42 189:649 -> ../bus/usb/006/010
lrwxrwxrwx 1 root root 18 2010-08-13 03:02 189:768 -> ../bus/usb/007/001
lrwxrwxrwx 1 root root 10 2010-08-13 03:02 1:9 -> ../urandom
lrwxrwxrwx 1 root root 12 2010-08-13 03:02 202:0 -> ../cpu/0/msr
lrwxrwxrwx 1 root root 12 2010-08-13 03:02 202:1 -> ../cpu/1/msr
lrwxrwxrwx 1 root root 12 2010-08-13 03:02 202:2 -> ../cpu/2/msr
lrwxrwxrwx 1 root root 14 2010-08-13 03:02 203:0 -> ../cpu/0/cpuid
lrwxrwxrwx 1 root root 14 2010-08-13 03:02 203:1 -> ../cpu/1/cpuid
lrwxrwxrwx 1 root root 14 2010-08-13 03:02 203:2 -> ../cpu/2/cpuid
Linux Char Vs block
$cd /dev/char/
$ ls –l
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 21:0 -> ../sg0
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 21:1 -> ../sg1
lrwxrwxrwx 1 root root 12 2010-08-13 03:02 226:0 -> ../dri/card0
lrwxrwxrwx 1 root root 17 2010-08-13 03:02 226:64 -> ../dri/controlD64
lrwxrwxrwx 1 root root 10 2010-08-13 03:02 250:0 -> ../hidraw0
lrwxrwxrwx 1 root root 10 2010-10-06 22:42 250:1 -> ../hidraw1
lrwxrwxrwx 1 root root 10 2010-08-13 03:02 251:0 -> ../usbmon0
…
lrwxrwxrwx 1 root root 10 2010-08-13 03:02 251:7 -> ../usbmon7
lrwxrwxrwx 1 root root 14 2010-08-13 03:02 252:0 -> ../bsg/0:0:0:0
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 254:0 -> ../rtc0
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 29:0 -> ../fb0
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 4:0 -> ../tty0
…
lrwxrwxrwx 1 root root 8 2010-08-13 03:02 4:38 -> ../tty38
lrwxrwxrwx 1 root root 10 2010-08-13 03:02 5:1 -> ../console
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 5:2 -> ../ptmx
lrwxrwxrwx 1 root root 6 2010-08-13 03:02 7:0 -> ../vcs
..
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 7:1 -> ../vcs6
lrwxrwxrwx 1 root root 7 2010-08-13 03:02 7:128 -> ../vcsa..
lrwxrwxrwx 1 root root 8 2010-08-12 21:32 7:134 -> ../vcsa6
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 7:2 -> ../vcs2
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 7:3 -> ../vcs3
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 7:4 -> ../vcs4
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 7:5 -> ../vcs5
lrwxrwxrwx 1 root root 7 2010-08-12 21:32 7:6 -> ../vcs6
lrwxrwxrwx 1 root root 11 2010-08-12 21:32 99:0 -> ../parport0
Basic char-driver components
init
exit
fops
function
function
function
. . .
Device-driver LKM layout
registers the ‘fops’
unregisters the ‘fops’
module’s ‘payload’
is a collection of
callback-functions
having prescribed
prototypes
AND
a ‘package’ of
function-pointers
the usual pair of
module-administration
functions
Character Device Drivers
Standard File-I/O functions
int open( char *pathname, int flags, … );
int read( int fd, void *buf, size_t count );
int write( int fd, void *buf, size_t count );
int lseek( int fd, loff_t offset, int whence );
int close( int fd );
(and other less-often-used file-I/O functions)
root# mknod /dev/cmos c 70 0
Read /dev/cmos as a FILE
Multi-tasking
Stacks and task-descriptors
What’s on a program’s stack?
Upon entering ‘main()’:
During execution of ‘main()’:
Entering the kernel…
A user process enters ‘kernel-mode’:
Switching to a different stack
e.g., user-mode stack might be exhausted
e.g, privileged data might be accessible
What’s on the kernel stack?
Upon entering kernel-mode:
(e.g., address of task’s user-mode stack)
During execution of kernel functions:
Supporting structures
A task’s virtual-memory layout
User space
Kernel space
User-mode stack-area
Task’s code and data
Privilege-level 0
Privilege-level 3
process descriptor
and
kernel-mode stack
Shared runtime-libraries
The Linux process descriptor
task_struct
state
*stack
flags
*mm
exit_code
*user
pid
*files
*parent
mm_struct
*pgd
pagedir[]
user_struct
signal_struct
*signal
files_struct
Each process
descriptor
contains many
fields
and some are
pointers to
other kernel
structures
which may
themselves
include fields
that point to
structures
Something new in 2.6
page-frame to store ‘thread information’
Task’s kernel-stack
Task’s thread-info
page-frame aligned
Task’s
process-descriptor
struct task_struct
8-KB
Tasks have ’states’
From kernel-header: <linux/sched.h>
Fields in a process-descriptor
struct task_struct {
volatile long state;
void *stack;
unsigned long flags;
struct mm_struct *mm;
struct thread_struct *thread;
pid_t pid;
char comm[16];
/* plus many other fields */
};
Finding a task’s ‘thread-info’
movl $0xFFFFF000, %eax
andl %esp, %eax
Ok, now %eax = the thread-info’s base-address
There’s a macro that implements this computation
Finding task-related kernel-data
struct thread_info *info = task_thread_info( task );
struct task_struct *task = info->task;
The kernel’s ‘task-list’
Doubly-linked circular list
init_task
(pid=0)
newest
task
…
next_task
prev_task
Maybe a big /proc file…
How to avoid buffer-overflow
offset == 0 and *start == NULL
Normal case
Alternative case
*start = buf;
The benefit
First pass
Final time
Our implementation
struct task_struct *task; // ‘global’ variables’ values remembered
int my_get_info( char *buf, char **start, off_t offset, int buflen )
{
int len = 0;
if ( offset == 0 ) // our first time through this function
{
task = &init_task; // start of circular linked-list
}
else if ( task == &init_task ) return 0; // our final pass
// put some data into the kernel-supplied buffer
len += sprintf( buf+len, “pid=%d \n”, task->pid );
*start = buf; // tell kernel where to find data, and to call again
task = next_task( task ); // advance to next node of circular list
return len; // and tell kernel how far to advance
}
‘Kernel threads’
Thanks