Using our device-driversThe ‘fileview.cpp’ applicationEasy file navigationThe ‘curses’ libraryConcept behind ‘curses’Using ‘ncurses’ with LinuxThe typical ‘curses’ programCompiling ‘ncurses’ programsSome frequent functionsReferenceUnusual goal of ‘fileview.cpp’Linux uses ‘glibc’ C-libraryCalling ‘llseek()’ anywaySome ‘macros’ make it easierA programming ‘bug’Why wasn’t ‘bug’ found?But project #3 is differentHow can ‘bug’ be fixed?Some pseudo-codeRecommendationsExercise‘sys_write( int fd, void *msg, int n)’Using our device-driversHow 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 necessaryEasy 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 formatThe ‘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 screenConcept 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-behaviorThe 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-callLinux uses ‘glibc’ C-library•The Gnu version of Standard C Library•‘glibc’ implements system-call interfaces for the standard UNIX C functions, likeopen(), 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 readretval = 0 : end-of-file reached, so no dataretval < 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 256But 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 occurHow 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()’ functionsSome pseudo-codeint 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()’ outputExercise•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
View Full Document