using our device-drivers how can an application display the data in a device special file?
Post on 02-Apr-2015
217 Views
Preview:
TRANSCRIPT
Using our device-drivers
How can an application display the data in a device special file?
The ‘fileview.cpp’ application
• Purpose: a tool for viewing arbitrary files
• Some files have ascii text
• Other files have binary data
• So display in both hexadecimal and ascii
• Some ascii characters are ‘control codes’
• Some bytes are not ascii characters at all
• So show a substitute mark as necessary
Easy file navigation
• Files may be quite large
• Can only fit small pieces on one screen
• And only some parts may be of interest
• Also some hex formats can be confusing
• Need a way to find what we want to see
• Need it to remain visible while we read it
• Need flexibility to adjust display format
The ‘curses’ library
• Offers users an ‘interactive’ interface
• Allows use of normal keyboard input
• Allows use of a mouse
• Allows use of ‘windows’ and ‘colors’
• Allows use cursor-keys for navigation
• Allows use of ‘unbuffered’ keystrokes
• Offers instant refresh of display screen
Concept behind ‘curses’
• Works on screens, windows, subwindows• Maintains several internal data-structures• Two of these are ‘stdscr’ and ‘curscr’• Both are ‘maps’ of your physical screen• Drawing is done to the ‘stdscr’ window• But it doesn’t show up immediately• ‘refresh()’: compares ‘stdscr’ to ‘curscr’ and
then only copies the parts that are ‘new’
Using ‘ncurses’ with Linux
• #include <curses.h>
• ‘initscr()’ initializes library data-structures
• ‘noecho()’ turns off keystroke echoing
• ‘raw()’ and ‘cbreak()’ set special behaviors
• ‘refresh()’ updates the display screen
• ‘endwin()’ restores normal tty-behavior
The typical ‘curses’ program
#include <unistd.h>#include <stdlib.h>#include <curses.h>
int main( int argc, char **argv ){
initscr();…endwin();
}
Compiling ‘ncurses’ programs
• Must use the ‘-l’ command-line switch:
• Example:
$ g++ fileview.cpp –lncurses –o fileview
• This is lowercase ‘L’ (not uppercase ‘i’)
• It means link with ‘libncurses.so’ library
• Object libraries are in directory: ‘/usr/lib’
Some frequent functions
• ‘clear()’
• ‘move()’
• ‘printw()’
• ‘mvprintw()’
• ‘refresh()’
• ‘newwin()’
• ‘box()’
Reference
• Good introductory tutorial appears in:
Richard Stones and Neil Matthew,
“Beginning Linux Programming (2nd Ed.)”
(WROX Press Ltd, 1999), Chapter 6.
Unusual goal of ‘fileview.cpp’
• Wanted to look at VERY large device-files
• Eample: /dev/hda
• This device file represents the hard disk
• Size of today’s hard disk could be 180GB!
• So file-positions could not be of type ‘long’
• Linux introduces a 64-bit type: loff_t
• Kernel offers ‘sys_llseek()’ system-call
Linux uses ‘glibc’ C-library
• The Gnu version of Standard C Library
• ‘glibc’ implements system-call interfaces
for the standard UNIX C functions, like
open(), close(), read(), write(), and lseek()
• But Gnu C Library omitted ‘llseek()’
• So can’t do seek-operations on big files!
Calling ‘llseek()’ anyway
• Programmers can call the kernel directly
• Can bypass the ‘glibc’ Standard C Library
• But need to obey system-call conventions
• Transition from user-mode to kernel-mode
• Requires use of a special CPU instruction
• This instruction is ‘architecture-specific’
• For Pentium CPU: asm(“ int $0x80 “);
Some ‘macros’ make it easier
• #include <asm/unistd.h>
• Calling ‘sys_llseek()’ requires 5 arguments
• Arguments must go into CPU registers
• ‘sys_call_table[ ]’ array-index goes in EAX
• The macro to use is named ‘_syscall5’
A programming ‘bug’
• Standard C ‘read()’ function returns ‘int’
• Meaning of the ‘read()’ return-value:retval > 0 : ‘retval’ bytes successfully read
retval = 0 : end-of-file reached, so no data
retval < 0 : some error prevented reading
• Return-value wasn’t checked in ‘fileview’!
Why wasn’t ‘bug’ found?
• ‘fileview’ always tried to read 256 bytes
• Never tried to read beyond ‘end-of-file’
• Never tried to read data that ‘wasn’t there’
• So no reason why retval wouldn’t be 256
But project #3 is different
• ‘ram.c’ must read ALL physical pages
• ‘high memory’ pages not always ‘mapped’
• And pages are not ‘mapped’ contiguously
• 256 bytes could cross a page-boundary– Starting address: 0x00000F80– Ending address: 0x00001080
• So some ‘read()’ errors could easily occur
How can ‘bug’ be fixed?
• Several solutions are possible
• Best to try minimizing the code-changes
• Should focus on correct ‘fix’ for all drivers
• Obey rules for driver ‘read()’ functions
Some pseudo-code
int my_read( int fd, char *cp, int count ){
int more = count;while ( more )
{int n = read( fd, cp, more );if ( n <= 0 ) return n;cp += n;more -= n;}
return count;}
Recommendations
• Consult “Linux Device Drivers” text
• ‘read()’ method is described on page 80
• Do everything that’s actually necessary
• But keep your code as simple as possible
• During development: use ‘printk()’ output
• For ‘release version’: omit ‘printk()’ output
Exercise
• Write a ‘hello world’ program in C
• But don’t use ANY header-files!!
• (i.e., bypass the Standard C Library)
• How?
• 1) setup static message-string
• 2) setup registers with parameters
• 3) use ‘int 0x80’ to enter the kernel
‘sys_write( int fd, void *msg, int n)’
• The system-call number is 4
• The STDOUT file-descriptor is 1
• The message-string address is $msg
• The message-length (you count the bytes)
• These 4 arguments go in CPU registers: EAX, EBX, ECX, EDX (in that order)
• So your ‘main()’ needs only 5 instructions!
top related