Character Driver Issues Implementing ‘/dev/physmem’
Goals for ‘physmem’ Let user-programs ‘read’ physical memory Make this convenient for the programmer Treat physical memory as just one big file Then can use standard C library functions: i.e., open(), lseek(), read(), close() But don’t give user-programs write-access!
The ‘mknod’ command Device-file: usually created by command # mknod /dev/physmem c ‘mknod’ takes 4 command-line arguments: the pathname of the special file ‘c’ indicates it’s a character device 251 is driver’s ID-number (i.e., major) 0 is the device’s ID-number (i.e., minor) Need ‘root’ privileges to create /dev file
Default file permissions Without ‘root’ privileges, we can’t try it But if we could, we’d see file-permissions Example: # mknod /dev/xxx c # ls -l /dev/xxx crw-r—r-- 1 root root 251, 0 25 Feb dev/xxx We don’t want users to ‘write’ to physmem
Modifying file-permissions Supervisor can change file-permissions ‘chmod’ is the privileged command to use Example: # chmod 0444 /dev/xxx # ls -l /dev/xxx cr--r—r-- 1 root root 251, 0 25 Feb dev/xxx Now the device-file has ‘read-only’ access
A ‘smarter’ driver Our drivers can create their own files: syscall: mknod( pathname, mode, devid); Our drivers can modify file-permissions: syscall: chmod( pathname, mode); Our drivers can also delete their own files: syscall: unlink( pathname );
Some manifest constants Header-file: #include #define S_IFCHR #define S_IRUSR #define S_IRGRP #define S_IROTH By ‘or’-ing the latter three values, can get: #define S_IRUGO
Driver’s ‘read()’ function Must conform to standard prototype Otherwise: can’t ‘register_chrdev()’ Return-value has type ‘ssize_t’ Function takes four arguments: struct file *filp;// pointer to file-structure char*buf; // pointer to user-buffer size_tcount; // size of user-buffer loff_t*pos; // points to file-position
Algorithm for ‘read()’ Step 1: Check for an invalid request: if ( *pos >= filesize ) return –EINVAL; Step 2: Adjust ‘count’ for remaining bytes: If ( *pos + count > filesize ) count = filesize - *pos;
Algorithm (continued) Step 3: Find location of next data bytes void *from = phys_to_virt( *pos ); Step 4: Copy data into user-space buffer more = copy_to_user( buf, from, count ); Step 5: Return error if copying unfinished if ( more ) return –EFAULT;
Algorithm (conclusion) Step 6: Advance file’s current position *pos += count; Step 7: Return number of bytes copied return count;
Driver needs ‘llseek()’ ‘fileview.cpp’ checks for size of device-file Standard C library function is ‘lseek()’: filesize = lseek( fd, 0, SEEK_END ); ‘fd’ is the file-descriptor for an opened file 0 is the ‘offset’ to seek to SEEK_END says offset is from end-of-file
Default ‘llseek()’ won’t work No way for kernel to know device’s filesize So default ‘llseek()’ will give a wrong result Driver must implement its own ‘llseek()’ For ‘/dev/physmen’ with 1GB memory: FILESIZE = 0x But more generally: FILESIZE = virt_to_phys( high_memory );
Sample ‘llseek()’ in LDD text ‘llseek()’ must handle three cases: #define SEEK_SET0 #define SEEK_CUR1 #define SEEK_END2 (See author’s example-code on page 163)
Prototype for ‘llseek()’ Function has three arguments: struct file *filp;// pointer to file-structure loff_t offset;// file-offset to seek to intwhence;// where to seek from Return-value has type ‘loff_t’ (new offset)
Algorithm for ‘llseek()’ Step 1: Use ‘switch’ statement: switch( whence ) { case 0:// for SEEK_SET case 1:// for SEEK_CUR case 2:// for SEEK_END default:// should never happen! }
Actions for ‘switch’ cases case SEEK_SET: newpos = offset; break; case SEEK_CUR: newpos = file->f_pos + offset; break; case SEEK_SET: newpos = filesize + offset; break; default: return -EINVAL;
Algotithm (conclusion) Step 2: Check for illegal ‘newpos’ value: if ( newpos < 0 ) return –EINVAL; Step 3: Update ‘f_pos’ in file-structure: filp->f_pos = newpos; Step 4: Return new file-pointer position: return newpos;
‘physmem’ is read-only If device-file lacks ‘write’ permissions, then kernel won’t call driver’s ‘write()’ function So omit write-function from device-driver in order to avoid having ‘dead code’
Consider your legacy Your driver-code may have a future life! Another programmer could ‘inherit’ it Or you, yourself, may want to ‘reuse’ it Keeping ‘dead code’ will cause confusion Omitting commentary will cause frustration Need the author’s name (and contact-info) Need code’s revision-history (when/why)