Download presentation
Presentation is loading. Please wait.
1
Standard C Libraries Application Programmming Interface to System-Calls
2
Important 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 );
3
UNIX ‘man’ pages A convenient online guide to prototypes and semantics of the C linrary functions Example of usage: $ man 2 open
4
The ‘open’ function #include int open( char *pathname, int flags, … ); Converts a pathname to a file-descriptor File-descriptor is a nonnegative integer Used as a file-ID in subsequent functions ‘flags’ is a symbolic constant: O_RDONLY, O_WRONLY, O_RDWR
5
The ‘close’ function #include int close( int fd ); Breaks link between file and file-descriptor Returns 0 on success, or -1 if an error
6
The ‘write’ function #include int write( int fd, void *buf, size_t count ); Attempts to write up to ‘count’ bytes Bytes are taken from ‘buf’ memory-buffer Returns the number of bytes written Or returns -1 if some error occurred Return-value 0 means no data was written
7
The ‘read’ function #include int read( int fd, void *buf, size_t count ); Attempts to read up to ‘count’ bytes Bytes are placed in ‘buf’ memory-buffer Returns the number of bytes read Or returns -1 if some error occurred Return-value 0 means ‘end-of-file’
8
Notes on ‘read()’ and ‘write()’ These functions have (as a “side-effect”) the advancement of a file-pointer variable They return a negative function-value of -1 if an error occurs, indicating that no actual data could be transferred; otherwise, they return the number of bytes read or written The ‘read()’ function normally does not return 0, unless ‘end-of-file’ is reached
9
The ‘lseek’ function #include off_t lseek( int fd, off_t offset, int whence ); Modifies the file-pointer variable, based on the value of whence: enum { SEEK_SET, SEEK_CUR, SEEK_END }; Returns the new value of the file-pointer (or returns -1 if any error occurred)
10
Getting the size of a file For normal files, your application can find out how many bytes belong to a file using the ‘lseek()’ function: int filesize = lseek( fd, 0, SEEK_END ); But afterward you need to ‘rewind’ the file if you want to read its data: lseek( fd, 0, SEEK_SET );
11
What about ‘pseudo’ files? You can use standard library functions to open, read, and close a ‘/proc’ pseudo-file You can use ‘lseek’ (except SEEK_END) An example is our ‘howfast.cpp’ program It measures how fast ‘jiffies’ increments It opens, reads, and closes ‘/proc/jiffies’ And it also uses ‘lseek’ (to rewind this file)
12
How these system-calls work Application Program User-spaceKernel-space C Runtime Library Operating System Kernel Module ‘methods’
13
Special ‘device’ files UNIX systems treat hardware-devices as special files, so that familiar functions can be used by application programmers to access these devices (open, read, close) But a System Administrator has to create these device-files (in the ‘/dev’ directory) There are two categories of device files: ‘character’ devices, and ‘block’ devices
14
The ‘mknod’ command To create the device-node for a character device, an Administrator executes ‘mknod’ root# mknod /dev/scull c 48 0 Here ‘/dev/scull’ is the file’s pathname, ‘c’ indicates that it’s a character-mode device, 48 is its (unique) ‘major’ ID-number, and 0 is its (unique) ‘minor’ ID-number Default access-privileges: r w - r - - r - - Can be modified using ‘chmod’ command
15
What’s new in 2.6? Earlier Linux kernels stored the ‘/dev’ files on the hard disk (so they were persistent) The 2.6 kernel stores them in a ram-disk So they ‘disappear’ during every shutdown You need ‘root’ privileges to re-build them! (Fortunately this step can be automated if device-nodes are in ‘/etc/udev/devices’ )
16
A useful device-driver We can create a character-mode driver for the processor’s physical memory (i.e. ram) (Our machines have 1-GB of physical ram) But another device-file is named ‘/dev/ram’ so ours will be: ‘/dev/dram’ (dynamic ram) We’ve picked 253 as its ‘major’ ID-number Our SysAdmin setup a device-node using: root# mknod /dev/dram c 253 0
17
Device knowledge Before you can write a device-driver, you must understand how the hardware works Usually this means you need to obtain the programmer manual (from manufacturer) Nowdays this can often be an obstacle But some equipment is standardized, or is well understood (because of its simplicity)
18
1-GB RAM has ‘zones’ ZONE_NORMAL ZONE_HIGH ZONE_LOW 128-MB 16-MB 1024-MB (= 1GB)
19
Legacy DMA Various older devices rely on the PC/AT’s DMA controller to perform data-transfers This chip could only use 24-bit addresses Only the lowest 16-megabytes of physical memory are ‘visible’ to these devices: 2 24 = 0x01000000 (16-megabytes) Linux tries to conserve its use of memory from this ZONE_LOW region for anything except DMA (so it will available if needed)
20
‘HIGH’ memory Linux traditionally tried to ‘map’ as much physical memory as possible into virtual addresses allocated to the kernel-space Before the days when systems had 1-GB or more of installed memory, Linux could linearly map ALL of the physical memory into the 1-GB kernel-region: 0xC0000000 – 0xFFFFFFFF But with 1GB there’s not enough room!
21
User space (3GB) The 896-MB limit Virtual address-space DRAM (1GB) Kernel space (1GB) HIGH MEMORY linearly mapped Physical address-space not-mapped 896-MB A special pair of kernel-functions named ‘kmap()’ and ‘kunmap()’ can be called by device-drivers to temporarily map pages of physical memory into ‘vacant’ areas within the kernel’s virtual address-space
22
‘copy_to_user()’ With kernel 2.6, it is possible to configure the user-space versus kernel-space ‘split’ so that nearly 4GB of physical memory is always linearly mapped into kernel-space The configuration-option is CONFIG_4GB With this option enabled, the user-space and kernel-space use two different maps So device-drivers need a special function to transfer kernel-data to a user’s buffer
23
Driver-module structure We will need three kernel header-files: –#include // for printk(), register_chrdev(), unregister_chrdev() –#include // for kmap(), kunmap(), and ‘num_physpages’ –#include // for copy_to_user()
24
Our ‘dram_size’ global Our ‘init_module()’ function will compute the size of the installed physical memory It will be stored in a global variable, so it can be accessed by our driver ‘methods’ It is computed from a kernel global using the PAGE_SIZE constant (=4096 for x86) dram_size = num_physpages * PAGE_SIZE
25
‘major’ ID-number Our ‘major’ device ID-number is needed when we ‘register’ our device-driver with the kernel (during initialization) and later when we ‘unregister’ our device-driver (during the cleanup procedure): int my_major = 253; // static ID-assignment
26
Our ‘file_operations’ Our ‘dram’ device-driver does not need to implement special ‘methods’ for doing the ‘open()’, ‘write()’, or ‘release()’ operations (the kernel ‘default’ operations will suffice) But we DO need to implement ‘read()’ and ‘llseek()’ methods Our ‘llseek()’ code here is very standard But ‘read()’ is specially crafted for DRAM
27
Using our driver We have provided a development tool on the class website (named ‘fileview.cpp’) which can be used to display the contents of files (including device-files) The data is shown in hex and ascii formats The arrow-keys can be used for navigation The enter-key allows an offset to be typed Keys ‘b’, ‘w’, ‘d’ and ‘q’ adjust data-widths
28
In-class exercise #1 Install the ‘dram.ko’ device-driver module; then use ‘fileview’ to browse the contents of the processor’s physical memory: $ fileview /dev/dram
29
Control Register CR3 Register CR3 holds the physical-address of the system’s current ‘page-directory’ The page-directory is an array of 1024 entries, showing how ‘virtual addresses’ are currently ‘mapped’ to physical pages With ‘fileview’ you can find and examine this important kernel data-structure – but you must know the value in register CR3
30
In-class exercise #2 Use the ‘newinfo’ wizard to quickly create a pseudo-file (named ‘/proc/cr3’) that will allow user-programs to obtain the current value of the Pentium’s CR3 register Write a tool (named ‘seepgdir.cpp’) that will read ‘/proc/cr3’ to get the address of the page-directory, then read it from the ‘/dev/dram’ device and print it onscreen
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.