How can an application display the data in a device special file?
• 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
• 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
• 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
• 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’
• #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
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
}
{ int main( int argc, char **argv ) initscr();
… endwin();
• 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’
• ‘clear()’
• ‘move()’
• ‘printw()’
• ‘mvprintw()’
• ‘refresh()’
• ‘newwin()’
• ‘box()’
• Good introductory tutorial appears in:
Richard Stones and Neil Matthew,
“Beginning Linux Programming (2 nd Ed.)”
(WROX Press Ltd, 1999), Chapter 6.
• 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
• 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!
• 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 “);
• #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’
• 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’!
• ‘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
• ‘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
• 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
}
{ 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;
• 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
• 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
• 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!