Title: Looking at kernel objects
1Looking at kernel objects
- How a character-mode Linux device driver can be
useful in viewing a net_device structure
2Our /proc/netdevs pseudo-file
- We wrote a Loadable Kernel Module that creates a
pseudo-file allowing users to see some
information about the kernels data
struct net_device
struct net_device
struct net_device
lo
eth0
eth1
3The LKMs source-code
netdevs.c
include ltlinux/module.hgt include
ltlinux/proc_fs.hgt char modname
netdevs MODULE_LICENSE(GP
L)
some header-files
some global data
my_get_info()
this modules payload function
module_init()
required module administration
functions
module_exit()
4User-space/Kernel-space
user-space (restricted privileges)
kernel-space (unrestricted privileges)
operating system kernel
LINUX
open read write (etc)
standard runtime library
application program
cat
netdevs.ko
installable module
privilege barrier
5Linux device drivers
- There is another kind of LKM, written to control
the systems hardware devices rather than merely
to expose information - Its code-structure will depend on the type of
hardware device it is intended to control - character devices
- block devices
- network interface devices
6Hardwares operations
- In order to write the software that controls a
particular device, the programmer needs to know
details about its capabilities and about its
mechanisms for being controlled - This information is found in programming manuals,
produced by the manufacturer - These manuals may or not be available to the
general public (often are proprietary)
7A few devices are simple
- If a particular devices operations are very
simple to understand, we may not need to consult
the manufacturers documentation (just use
common sense and guesswork) - EXAMPLE The computer systems main memory offers
us an easy-to-understand hardware component for
which we can directly write a device-driver
module
8dram.c
- Two benefits of having a device-driver for the
computers physical memory are - We can directly look at kernel data-structures
using unprivileged application-programs - We get to see the general code-structure for
Linux device-drivers in the simplest of cases
9Using our fileview utility
- Our previous netdevs.c module tells us where
the struct net_device objects are located in
our systems physical memory - So we can use fileview to inspect these kernel
data-structures once weve loaded our dram.ko
device-driver into the kernel
Timeout for an in-class demonstration
10The code-structure for dram.c
dram.c
include ltlinux/module.hgt include
ltlinux/highmem.hgt char modname dram int
my_major 85 MODULE_LICENSE(
GPL)
some header-files
some global data
this modules payload (its method
functions and its file_operations
structure)
my_read()
my_llseek()
my_fops
module_init()
required module administration
functions
module_exit()
11Kernels helper-functions
- The Linux kernel provides quite a few aids to the
authors of device-driver code - register_chrdev() and unregister_chrdev()
- copy_to_user() and copy_from_user()
- kmap() and kunmap()
- The kernel also exports some of its global
variables (which drivers can reference) - num_physpages and mem_map
12Memory-mapping
persistent mapping transient mappings
kernel space
HMA
user space
896-MB
physical RAM
There is more physical RAM in our classrooms
systems than can be mapped into the
available address-range for kernel virtual
addresses
CPUs virtual address-space
13What does kmap() do?
- The kmap() helper-function allows your driver
to create a temporary mapping for any one 4-KB
page of physical memory to some unused virtual
address in kernel-space, then later kunmap()
lets your driver discard that mapping when its
no longer needed (so there will be available that
kernel-address for later reuse)
14The mem_map array
- The kernel creates an array of structures, named
mem_map , whose entries hold detailed
information about how each 4KB page of physical
RAM is now being used - The global variable named phys_mem stores the
total number of array-entries, and hence can be
used by your driver to determine the amount of
installed RAM
15The function-prototypes
void kmap( struct page page_ptr ) This
function accepts a pointer to an entry of type
struct page in the kernels mem_map
array, and returns a kernel address where that
page of physical RAM has been temporarily mapped
void kunmap( void virt_addr ) This function
accepts an address where the kernel temporarily
has mapped a page of physical RAM and it deletes
that mapping, thus freeing the address for reuse
later when the kernel is asked to setup a
different temporary mapping of physical RAM into
kernel-space
16Our driver read() method
- It has to support the traditional stream-of-bytes
paradigm, so a sanity check will be needed for
the callers argument-values
ssize_t my_read( struct file file, char buf,
size_t count, loff_t pos )
number of bytes that caller wants to read
the current position of the file-pointer
// Theres nothing to be read beyond the
end of physical RAM if ( pos gt dram_size
) return 0
Physical RAM
dram_size
pos
17read() method (continued)
- Our driver has to accommodate the CPUs
page-granular memory-architecture, and the
kmap() functions ability to map
one-page-at-a-time
pos
int page_number pos / PAGE_SIZE
int page_indent pos PAGE_SIZE if (
page_indent count gt PAGE_SIZE ) count
PAGE_SIZE page_indent struct page pp
mem_map page_number void from kmap( pp
) page_indent int more copy_to_user( buf,
from, count )
18Another argument-value pitfall
- It is possible that the caller did not supply a
large-enough buffer for the amount of data that
is supposed to be transferred - That potential buffer-overflow problem could
be detected during execution of the
copy_to_user() helper-function, if fewer than
count bytes can be copied without triggering a
segmentation violation
19The drivers solution
- The copy_to_user() function return the number
of bytes that remain to be copied (normally this
is zero all copying got done) - But if its NOT zero, the drivers duty is to
notify the user that a segmentation fault error
occurred but AFTER kunmap()
int more copy_to_user( buf, from, count
) // first unmap the page, then notify the
user if necessary kunmap( pp ) if ( more )
return EFAULT
20The llseek() method
- Our dram.c driver needs to implement its own
llseek() function, in order to allow an
application-program to seek to the end of the
device-file (so it will know what total amount of
physical RAM is installed) - This feature is used by our fileview tool when
a user hits the ltENDgt-key, and to display the
total size for the device-file
21llseek() implementation
unsigned int dram_size // equals PAGE_SIZE
num_physpages loff_t my_llseek( struct file
file, loff_t offset, int whence )
loff_t newpos -1 switch ( whence
) case 0 newpos offset break //
SEEK_SET case 1 newpos file-gtf_pos offset
break // SEEK_CUR case 2 newpos dram_size
offset break // SEEK_END if ((
newpos lt 0 )( newpos gt dram_size )) return
EINVAL file-gtf_pos newpos return newpos
22Demo vwnetdev.cpp
- This application makes use of information from
the /proc/netdevs pseudo-file, plus the
information that can be read from the computers
physical memory using the capabilities
implemented by our dram.c device-driver - It lets a user view the struct net_device
object for a specified network-interface
23Our offsets.c module
- This module creates a pseudo-file that can help a
user to interpret the hexadecimal output produced
by vwnetdev - It shows the locations within a net_device
structure for some structure-members of
particular significance for network device
drivers (which we shall explore next time)
24In-class exercise 1
- One of the struct net_device fields that is
significant in a Linux network device driver is
the get_stats function-pointer field - Modify our offsets.c module so that the
pseudo-file this module creates will include the
offset for the get_stats member - Turn in a printout of the enhanced output
(created using our ljpages printing tool) be
sure your name is handwritten on it
25In-class exercise 2
- Take a look at our kernels definition for a
struct net_device object, in header-file - lt/usr/src/linux/include/linux/netdevice.hgt
- and identify three additional member-fields
that you would like to show the offsets for - Then implement the display of those three offsets
(by adding code to our offsets.c)