mirror of https://github.com/dzavalishin/oskit/
910 lines
32 KiB
TeX
Executable File
910 lines
32 KiB
TeX
Executable File
%
|
|
% Copyright (c) 1996-1998, 2000, 2001 University of Utah and the Flux Group.
|
|
% All rights reserved.
|
|
%
|
|
% The University of Utah grants you the right to copy and reproduce this
|
|
% document or portions thereof for academic, research, evaluation, and
|
|
% personal use only, provided that (1) the title page appears prominently,
|
|
% and (2) these copyright and permission notices are retained in all copies.
|
|
% To arrange for alternate terms, contact the University of Utah at
|
|
% csl-dist@cs.utah.edu or +1-801-585-3271.
|
|
%
|
|
\label{linux-dev}
|
|
|
|
The Linux device driver library consists of various native Linux
|
|
device drivers coupled with glue code to export the \oskit{}
|
|
interfaces such as blkio, netio, and bufio (See Chapter~\ref{oskit-io}).
|
|
See the source file \texttt{linux/dev/README} for a list of devices and
|
|
their status.
|
|
|
|
The header files \texttt{oskit/dev/linux_ethernet.h} and
|
|
\texttt{oskit/dev/linux_scsi.h} determine which network and SCSI
|
|
drivers are compiled into \texttt{liboskit_linux_dev.a}.
|
|
Those files also influence driver probing;
|
|
see the \texttt{oskit_linux_init} routines below.
|
|
|
|
|
|
\apisec{Initialization and Registration}
|
|
|
|
There are several ways to initalize this library.
|
|
One can either initialize all the compiled-in drivers
|
|
(\texttt{oskit_\-linux_\-init_\-devs},
|
|
initialize a specific class of drivers
|
|
(\texttt{oskit_\-linux_\-init_\-ethernet}),
|
|
or initialize specific drivers
|
|
(e.g., \texttt{oskit_\-linux_\-init_\-scsi_\-ncr53c8xx}).
|
|
|
|
These initialization functions initialize various glue code and
|
|
register the appropriate device(s) in the device tree,
|
|
to be probed with \texttt{oskit_dev_probe}.
|
|
|
|
\api{oskit_linux_init_devs}{Initialize and register all known drivers}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_devs(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers all known drivers.
|
|
The known drivers are: the IDE disk driver, and all drivers
|
|
listed in the \texttt{<oskit/dev/linux_ethernet.h>} and
|
|
\texttt{<oskit/dev/linux_scsi.h>} files.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_net}{Initialize and register known network drivers}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_net(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers all available network drivers.
|
|
Currently this means Ethernet drivers only,
|
|
but in the future there may be other network drivers supported such
|
|
as Myrinet.
|
|
The known Ethernet drivers are listed in the
|
|
\texttt{<oskit/dev/linux_ethernet.h>} file.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_ethernet}{Initialize and register known Ethernet network drivers}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_ethernet(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers all available Ethernet
|
|
network drivers.
|
|
The known Ethernet drivers are listed in the
|
|
\texttt{<oskit/dev/linux_ethernet.h>} file.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_scsi}{Initialize and register known SCSI disk drivers}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_scsi(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers all available SCSI disk drivers.
|
|
The known SCSI drivers are listed in the
|
|
\texttt{<oskit/dev/linux_scsi.h>} file.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_ide}{Initialize and register known IDE disk drivers}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_ide(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers all available IDE disk drivers.
|
|
There is currently only one IDE driver.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_scsi_\emph{name}}{Initialize and register a specific SCSI disk driver}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_scsi_\emph{name}(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers a specific SCSI disk driver.
|
|
The \emph{name} must be one from the \texttt{name} field of the drivers
|
|
listed in the
|
|
\texttt{<oskit/dev/linux_scsi.h>} file.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\api{oskit_linux_init_ethernet_\emph{name}}{Initialize and register a specific Ethernet network driver}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto void oskit_linux_init_ethernet_\emph{name}(void);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function initializes and registers a specific Ethernet
|
|
network driver.
|
|
The \emph{name} must be one from the \texttt{name} field of the drivers
|
|
listed in the
|
|
\texttt{<oskit/dev/linux_ethernet.h>} file.
|
|
|
|
Once drivers are registered, their devices may be probed
|
|
via \texttt{oskit_dev_probe}.
|
|
\end{apidesc}
|
|
|
|
|
|
\apisec{Obtaining object references}
|
|
|
|
Once the desired drivers are initialized, registered, and probed,
|
|
one can obtain references to their \texttt{blkio}, \texttt{netio}, etc
|
|
interfaces (See Chapter~\ref{oskit-io}) two different ways.
|
|
|
|
The first way is to look them up via their Linux name, e.g., ``sd0'' for
|
|
a SCSI disk, or ``eth0'' for a Ethernet device.
|
|
This is described here as it is specific to Linux.
|
|
|
|
The second, and preferred, way is to use \texttt{osenv_\-device_\-lookup}
|
|
to find a detected device with the desired interface, such as
|
|
\texttt{oskit_\-etherdev_\-iid} (See Chapter~\ref{libfdev}).
|
|
|
|
|
|
% We only describe oskit_linux_block_open because that is the only
|
|
% one that is actually used in the examples.
|
|
|
|
\api{oskit_linux_block_open}{Open a disk given its Linux name}
|
|
\begin{apisyn}
|
|
\cinclude{oskit/dev/linux.h}
|
|
|
|
\funcproto oskit_error_t oskit_linux_block_open(const char *name,
|
|
unsigned flags,
|
|
\outparam oskit_blkio_t **out_io);
|
|
\end{apisyn}
|
|
\begin{apidesc}
|
|
This function takes a Linux name of a disk,
|
|
e.g., ``sd0'' or ``wd1'',
|
|
and returns an \texttt{oskit_blkio_t} that can be used to access
|
|
the device.
|
|
|
|
The \texttt{oskit_blkio} interface is described in
|
|
Chapter~\ref{oskit-io}.
|
|
\end{apidesc}
|
|
\begin{apiparm}
|
|
\item[name]
|
|
The Linux name of the device
|
|
e.g., ``sd0'' or ``wd1''.
|
|
|
|
\item[flags]
|
|
Formed by or'ing the following values:
|
|
\begin{description}
|
|
\item[OSKIT_DEV_OPEN_READ]
|
|
\item[OSKIT_DEV_OPEN_WRITE]
|
|
\item[OSKIT_DEV_OPEN_ALL]
|
|
\end{description}
|
|
|
|
\item[out_io]
|
|
Upon success, is set to point to an \texttt{oskit_blkio_t}
|
|
that can be used to access the device.
|
|
\end{apiparm}
|
|
\begin{apiret}
|
|
Returns 0 on success, or an error code specified in
|
|
{\tt <oskit/error.h>}, on error.
|
|
\end{apiret}
|
|
|
|
|
|
\api{oskit_linux_block_open_kdev}{Open a disk given its Linux kdev}
|
|
|
|
|
|
\api{oskit_linux_netdev_find}{Open a netcard given its Linux name}
|
|
|
|
|
|
\api{oskit_linux_net_open}{Open a netcard given its Linux name}
|
|
|
|
|
|
\newpage
|
|
\emph{The rest of this chapter is very incomplete.
|
|
Some of the internal details of the Linux driver emulation are described,
|
|
but not the aspects relevant for typical use of the library.}
|
|
|
|
\section{Introduction}
|
|
|
|
XXX
|
|
|
|
\emph{Much of the data here on Linux device driver internals
|
|
is out-of-date with respect to the newer device drivers that are now
|
|
part of the \oskit{}. This section documents drivers from Linux
|
|
1.3.6.8 or earlier; the current \oskit{} drivers are from Linux
|
|
2.2.12, so parts of this section are likely no longer correct.}
|
|
|
|
|
|
XXX Library can be used either as one component
|
|
or can be used to produce many separate components,
|
|
depending on how it is used.
|
|
|
|
\section{Partially-compliant Drivers}
|
|
|
|
There are a number of assumptions made by \emph{some} drivers:
|
|
if a given assumption is not met by the OS using the framework,
|
|
then the drivers that make the assumption will not work,
|
|
but other drivers may still be usable.
|
|
The specific assumptions made by each partially-compliant driver
|
|
are listed in a table in the appropriate section below;
|
|
here is a summary of the assumptions some of the drivers make:
|
|
\begin{itemize}
|
|
\item Kernel memory can be allocated from interrupt handlers.
|
|
\item Drivers can allocate contiguous chunks of physical memory
|
|
larger than one page.
|
|
\item (x86) Drivers can allocate memory specifically in the low 16MB
|
|
of memory accessible to the PC's built-in DMA controller.
|
|
\item Drivers can sleep uninterruptibly.
|
|
\item Drivers can access the clock timer and DMA registers directly.
|
|
\item ``Poll-and-Yield:'' polls for short
|
|
periods of time and yields the CPU without explicitly going to sleep.
|
|
|
|
\end{itemize}
|
|
|
|
\section{Internals}
|
|
|
|
The following sections document all the variables and functions that Linux
|
|
drivers can refer to.
|
|
These variables and functions are provided by the glue code
|
|
supplied as part of the library,
|
|
so this information should not be needed for normal use of the library
|
|
under the device driver framework.
|
|
However, they are documented here
|
|
for the benefit of those working on this library
|
|
or upgrading it to new versions of the Linux drivers,
|
|
or for those who wish to ``short-cut'' through the framework
|
|
directly to the Linux device drivers in some situations,
|
|
e.g., for performance reasons.
|
|
|
|
|
|
\subsection{Namespace Management Rules}
|
|
|
|
\sloppy{%
|
|
For an outline of our namespace management conventions,
|
|
see Section 4.7.2 in our SOSP paper,
|
|
\htmladdnormallink{http://www.cs.utah.edu/flux/papers/index.html\#SOSKIT}%
|
|
{http://www.cs.utah.edu/flux/papers/index.html\#SOSKIT}.
|
|
}
|
|
|
|
% doc/papers/oskit-sosp16.ps. ....sorry, this has copyright problems.
|
|
|
|
\com{%
|
|
XXX make this fit.
|
|
|
|
To address preprocessor and type conflicts and the like,
|
|
the rule is that imported OS code _only_ includes its native headers
|
|
plus any ``glue'' headers that we write specifically for that OS\@.
|
|
In other words, the Linux drivers should definitely never see <oskit/page.h>
|
|
or any of the other \oskit\ header files outside the linux_dev package.
|
|
(The specific problem above is that Linux's <asm-i386/page.h>
|
|
was changed to include <oskit/page.h>, which it shouldn't do.)
|
|
The fdev glue code specific to a particular OS (e.g., linux/dev/*.c)
|
|
can include that OS's headers, the glue headers specific to that OS,
|
|
_and_ the generic fdev headers defining the fdev interfaces (fdev/*.h),
|
|
but must not include any other \oskit\ headers.
|
|
Clients of these device drivers and all other code outside a driver set
|
|
must never include any of the native OS headers used within the driver set;
|
|
this is already enforced by the native OS include directory
|
|
being a private subdirectory in the driver set (e.g., linux_fdev/include/)
|
|
rather than a subdirectory of the public header file directory (oskit/).
|
|
By following these rules, imported OS symbols never touch
|
|
any symbols defined by the \oskit\ or the client OS,
|
|
with the exception of the fdev/* headers defining the interface between the two;
|
|
and _all_ of the symbols in these fdev headers are prefixed with `fdev_'.
|
|
|
|
To address linker namespace conflicts,
|
|
the rule is that _all_ global linker symbols used in a given driver set
|
|
must be given a common prefix for that driver set, e.g., `fdev_linux_'.
|
|
Global symbols defined by the glue code for that driver set,
|
|
either to be publicly exported to clients or merely for internal use,
|
|
must be named according to this convention from the outset.
|
|
(For example, see oskit_linux_dev_init() or oskit_linux_block_open().)
|
|
Global symbols defined or used by the native OS code being imported
|
|
must be given this common prefix using appropriate preprocessor magic.
|
|
Specifically, I've created (but not yet checked in)
|
|
a Linux glue-code header file called `global.h'
|
|
that simply consists of a bunch of #define's to add this prefix.
|
|
In linux/dev/GNUmakerules, I've added a magic GCC flag
|
|
causing this header file to be included at the top of _all_ linux/dev sources,
|
|
including both the glue code sources and the raw Linux sources.
|
|
This means that both the Linux glue code and the Linux code itself
|
|
can use the plain Linux symbols and be oblivious to the fact
|
|
that they're getting prefixed.
|
|
The initial global.h I created is consistent with the set
|
|
of global variables and functions Shantanu documented in linux-dev.tex.
|
|
Naturally, there are quite a few more that need to be added,
|
|
some because they were originally missed or appeared in the Linux-2.0 upgrade,
|
|
others because they are both defined and used by the drivers themselves
|
|
and thus never appeared to us as ``undefined symbols'' on linker runs
|
|
(e.g., the SCSI globals used by the various SCSI-related drivers).
|
|
Although it may sound like a pain to keep this list up-to-date,
|
|
it is really quite trivial to find any symbols we missed using nm and grep.
|
|
Also, a lot of the remaining global symbols look like they don't need to be,
|
|
and we can probably address them by sending patches to the Linux people.
|
|
|
|
>you said that the files belonging to BSD should only see the
|
|
>BSD header files, and that only the glue code would see both.
|
|
>
|
|
>However, take the case of `struct proc'. Clearly, to implement
|
|
>sleep/wakeup, this struct must be enhanced with a osenv_sleeprec_t,
|
|
>thus requiring to double definitions or to pull in the dev header
|
|
>tree in all files including sys/proc.h (practically all.)
|
|
|
|
Good point. Yes, it's probably OK to pull in fdev header files
|
|
from modified BSD include files (we do that in Linux already),
|
|
since all of the fdev symbols defined should have a disambiguating prefix.
|
|
I guess the rule will have to be that the native BSD code
|
|
only _directly_ includes native BSD header files.
|
|
|
|
}%com
|
|
|
|
\subsection{Variables}
|
|
|
|
\begin{icsymlist}
|
|
\item[current]
|
|
|
|
This is a global variable that points to the state for the current
|
|
process. It is mostly used by drivers to set or clear the
|
|
interruptible state of the process.
|
|
|
|
\item[jiffies]
|
|
|
|
Many Linux device drivers depend on a global variable called {\tt jiffies},
|
|
which in Linux contains a clock tick counter
|
|
that is incremented by one at each 10-millisecond (100Hz) clock tick.
|
|
The device drivers typically read this counter while polling a device
|
|
during a (hopefully short) interrupt-enabled busy-wait loop.
|
|
Although a few drivers
|
|
take the global clock frequency symbol {\tt HZ} into account
|
|
when determining timeout values and such,
|
|
most of the drivers just used hard-coded values
|
|
when using the {\tt jiffies} counter for timeouts,
|
|
and therefore assume that {\tt jiffies} increments
|
|
``about'' 100 times per second.
|
|
|
|
\item[irq2dev_map]
|
|
|
|
This variable is an array of pointers to network device structures.
|
|
The array is indexed by the interrupt request line (IRQ) number.
|
|
Linux network drivers use it in interrupt handlers to find the
|
|
interrupting network device given the IRQ number passed to them by the
|
|
kernel.
|
|
|
|
\item[blk_dev]
|
|
|
|
This variable is an array of ``struct blk_dev_struct'' structures. It
|
|
is indexed by the major device number. Each element contains the I/O
|
|
request queue and a pointer to the I/O request function in the
|
|
driver. The kernel queues I/O requests on the request queue, and calls
|
|
the request function to process the queue.
|
|
|
|
\item[blk_size]
|
|
|
|
This variable is an array of pointers to integers. It is indexed by
|
|
the major device number. The subarray is indexed by the minor device
|
|
number. Each cell of the subarray contains the size of the device in
|
|
1024 byte units. The subarray pointer can be NULL, in which case, the
|
|
kernel does not check the size and range of an I/O request for the device.
|
|
|
|
\item[blksize_size]
|
|
|
|
This variable is an array of pointers to integers. It is indexed by
|
|
the major device number. The subarray is indexed by the minor device
|
|
number. Each cell of the subarray contains the block size of the
|
|
device in bytes. The subarray can be NULL, in which case, the kernel
|
|
uses the global definition BLOCK_SIZE (currently 1024 bytes) in its
|
|
calculations.
|
|
|
|
\item[hardsect_size]
|
|
|
|
This variable is an array of pointers to integers. It is indexed by
|
|
the major device number. The subarray is indexed by the minor device
|
|
number. Each cell of the subarray contains the hardware sector size of the
|
|
device in bytes. If the subarray is NULL, the kernel uses 512 bytes
|
|
in its calculations.
|
|
|
|
\item[read_ahead]
|
|
|
|
This variable is an array of integers indexed by the major device
|
|
number. It specifies how many sectors of read-ahead the kernel should
|
|
perform on the device. The drivers only initialize the values in this
|
|
array; the Linux kernel block buffer code is the actual user of these
|
|
values.
|
|
|
|
\item[wait_for_request]
|
|
|
|
The Linux kernel uses a static array of I/O request structures. When
|
|
all I/O request structures are in use, a process sleeps on this
|
|
variable. When a driver finishes an I/O request and frees the I/O
|
|
request structure, it performs a wake up on this variable.
|
|
|
|
\item[EISA_bus]
|
|
|
|
If this variable is non-zero, it indicates that the machine has an
|
|
EISA bus. It is initialized bye the Linux kernel prior to device
|
|
configuration.
|
|
|
|
\item[high_memory]
|
|
|
|
This variable contains the address of the last byte of physical memory
|
|
plus one. It is initialized by the Linux kernel prior to device
|
|
configuration.
|
|
|
|
\item[intr_count]
|
|
|
|
This variable gets incremented on entry to an interrupt handler,
|
|
and decremented on exit. Its purpose is let driver code determine if it
|
|
was called from an interrupt handler.
|
|
|
|
\item[kstat]
|
|
|
|
This variable contains Linux kernel statistics counters. Linux
|
|
drivers increment various fields in it when certain events occur.
|
|
|
|
\item[tq_timer]
|
|
|
|
Linux has a notion of ``bottom half'' handlers. These handlers have a
|
|
higher priority than any user level process but lower priority than
|
|
hardware interrupts. They are analogous to software interrupts in
|
|
BSD\@. Linux checks if any ``bottom half'' handlers need to be run when
|
|
it is returning to user mode. Linux provides a number of lists of
|
|
such handlers that are scheduled on the occurrence of specific events.
|
|
{\tt tq_timer} is one such list. On every clock interrupt,
|
|
Linux checks if any handlers are on this list, and if there are,
|
|
immediately schedules the handlers to run.
|
|
|
|
\com{%
|
|
This is only used by dev.c which is not a driver. I am not sure
|
|
if I should include it here.
|
|
|
|
\item[bh_base]
|
|
|
|
This variable is an array of ``struct bh_struct'' elements. It is
|
|
indexed by global constants defined in <linux/interrupt.h>. Each
|
|
element of this array contains a pointer to a function and a pointer
|
|
to an opaque data item which is passed to the function when it is
|
|
invoked. The array holds the list of software interrupt handlers.
|
|
Driver can directly add an entry in the array, and the Linux kernel
|
|
arranges for the handlers to be invoked at the appropriate junction.
|
|
}
|
|
|
|
\item[timer_active]
|
|
|
|
This integer variable indicates which of the timers in {\tt timer_table}
|
|
(described below) are active. A bit is set if the timer is active,
|
|
otherwise it is clear.
|
|
|
|
\item[timer_table]
|
|
|
|
This variable is an array of ``struct timer_struct'' elements. The
|
|
array is index by global constants defined in <linux/timer.h>. Each
|
|
element contains the duration of timeout, and a pointer to a function
|
|
that will be invoked when the timer expires.
|
|
|
|
\item[system_utsname]
|
|
|
|
This variable holds the Linux version number. Some drivers check the
|
|
kernel version to account for feature differences between different
|
|
kernel releases.
|
|
\end{icsymlist}
|
|
|
|
\subsection{Functions}
|
|
|
|
\begin{icsymlist}
|
|
\item[autoirq_setup]
|
|
\funcproto int autoirq_setup(int waittime);
|
|
|
|
This function is called by a driver to set up for probing IRQs.
|
|
The function attaches a handler on each available IRQ, waits
|
|
for \emph{waittime} ticks, and returns a bit mask of IRQs available
|
|
IRQs. The driver should then force the device to generate an interrupt.
|
|
|
|
\item[autoirq_report]
|
|
\funcproto int autoirq_report(int waittime);
|
|
|
|
This function is called by a driver after it has programmed the device
|
|
to generate an interrupt. The function waits \emph{waittime} ticks, and
|
|
returns the IRQ number on which the device interrupted. If no
|
|
interrupt occurred, 0 is returned.
|
|
|
|
\item[register_blkdev]
|
|
\funcproto int register_blkdev(unsigned major, const char *name,
|
|
struct~file_operations *fops);
|
|
|
|
This function registers a driver for the major number \emph{major}.
|
|
When an access is made to a device with the specified major number,
|
|
the kernel accesses the driver through the operations vector \emph{fops}.
|
|
The function returns 0 on success, non-zero otherwise.
|
|
|
|
\item[unregister_blkdev]
|
|
\funcproto int unregister_blkdev(unsigned major, const char *name);
|
|
|
|
This function removes the association between a driver and the major
|
|
number \emph{major}, previously established by {\tt register_blkdev}.
|
|
The function returns 0 on success, non-zero otherwise.
|
|
|
|
\item[getblk]
|
|
\funcproto struct~buffer_head *getblk(kdev_t dev, int block, int size);
|
|
|
|
This function is called by a driver to allocate a buffer \emph{size} bytes in
|
|
length and associate it with device \emph{dev}, and block number \emph{block}.
|
|
|
|
\item[brelse]
|
|
\funcproto void brelse(struct~buffer_head *bh);
|
|
|
|
This function frees the buffer \emph{bh}, previously allocated by
|
|
{\tt getblk}.
|
|
|
|
\item[bread]
|
|
\funcproto struct~buffer_head *bread(kdev_t dev, int block, int size);
|
|
|
|
This function allocates a buffer \emph{size} bytes in length, and fills
|
|
it with data from device \emph{dev}, starting at block number \emph{block}.
|
|
|
|
\item[block_write]
|
|
\funcproto int block_write(struct~inode *inode, struct~file *file,
|
|
const char *buf, int count);
|
|
|
|
This function is the default implementation of file write. It is used
|
|
by most of the Linux block drivers. The function writes \emph{count}
|
|
bytes of data to the device specified by \emph{i_rdev} field of
|
|
\emph{inode}, starting at byte offset specified by \emph{f_pos} of
|
|
\emph{file}, from the buffer \emph{buf}. The function returns 0 for
|
|
success, non-zero otherwise.
|
|
|
|
\item[block_read]
|
|
\funcproto int block_read(struct~inode *inode, struct~file *file,
|
|
const char *buf, int count);
|
|
|
|
This function is the default implementation of file read. It is used
|
|
by most of the Linux block drivers. The function reads \emph{count}
|
|
bytes of data from the device specified by \emph{i_rdev} field of
|
|
\emph{inode}, starting at byte offset specified by \emph{f_pos} field of
|
|
\emph{file}, into the buffer \emph{buf}. The function returns 0 for
|
|
success, non-zero otherwise.
|
|
|
|
\item[check_disk_change]
|
|
\funcproto int check_disk_change(kdev_t dev);
|
|
|
|
This function checks if media has been removed or changed in a
|
|
removable medium device specified by \emph{dev}. It does so by invoking the
|
|
\emph{check_media_change} function in the driver's file operations
|
|
vector. If a change has occurred, it calls the driver's \emph{revalidate}
|
|
function to validate the new media. The function returns 0 if no
|
|
medium change has occurred, non-zero otherwise.
|
|
|
|
\item[request_dma]
|
|
\funcproto int request_dma(unsigned drq, const char *name);
|
|
|
|
This function allocates the DMA request line \emph{drq} for the calling
|
|
driver. It returns 0 on success, non-zero otherwise.
|
|
|
|
\item[free_dma]
|
|
\funcproto void free_dma(unsigned drq);
|
|
|
|
This function frees the DMA request line \emph{drq} previously
|
|
allocated by {\tt request_dma}.
|
|
|
|
\item[disable_irq]
|
|
\funcproto void disable_irq(unsigned irq);
|
|
|
|
This function masks the interrupt request line \emph{irq} at the
|
|
interrupt controller.
|
|
|
|
\item[enable_irq]
|
|
\funcproto void enable_irq(unsigned irq);
|
|
|
|
This function unmasks the interrupt request line \emph{irq} at the
|
|
interrupt controller.
|
|
|
|
\item[request_irq]
|
|
\funcproto int request_irq(unsigned~int irq,
|
|
void (*handler)(int, struct),
|
|
unsigned long flags,
|
|
const char *device);
|
|
|
|
This function allocates the interrupt request line \emph{irq}, and
|
|
attach the interrupt handler \emph{handler} to it. It returns 0 on
|
|
success, non-zero otherwise.
|
|
|
|
\item[free_irq]
|
|
\funcproto void free_irq(unsigned int irq);
|
|
|
|
This function frees the interrupt request line \emph{irq}, previously
|
|
allocated by {\tt request_irq}.
|
|
|
|
\item[kmalloc]
|
|
\funcproto void *kmalloc(unsigned~int size, int priority);
|
|
|
|
This function allocates \emph{size} bytes memory.
|
|
The \emph{priority} argument is a set of bitfields defined as follows:
|
|
\begin{icsymlist}
|
|
\item[GFP_BUFFER] Not used by the drivers.
|
|
\item[GFP_ATOMIC] Caller cannot sleep.
|
|
\item[GFP_USER] Not used by the drivers.
|
|
\item[GFP_KERNEL] Memory must be physically contiguous.
|
|
\item[GFP_NOBUFFER] Not used by the drivers.
|
|
\item[GFP_NFS] Not used by the drivers.
|
|
\item[GFP_DMA] Memory must be usable by the DMA controller.
|
|
This means, on the x86, it must be below 16 MB, and
|
|
it must not cross a 64K boundary. This flag implies
|
|
GFP_KERNEL.
|
|
\end{icsymlist}
|
|
|
|
\item[kfree]
|
|
\funcproto void kfree(void *p);
|
|
|
|
This function frees the memory \emph{p} previously allocated by
|
|
{\tt kmalloc}.
|
|
|
|
\item[vmalloc]
|
|
\funcproto void *vmalloc(unsigned long size);
|
|
|
|
This function allocates \emph{size} bytes of memory in kernel
|
|
virtual space that need not have underlying contiguous physical memory.
|
|
|
|
\item[check_region]
|
|
\funcproto int check_region(unsigned port, unsigned size);
|
|
|
|
Check if the I/O address space region starting at \emph{port} and
|
|
\emph{size} bytes in length, is available for use. Returns 0 if region is
|
|
free, non-zero otherwise.
|
|
|
|
\item[request_region]
|
|
\funcproto void request_region(unsigned port, unsigned size,
|
|
const char *name);
|
|
|
|
Allocate the I/O address space region starting at \emph{port} and
|
|
\emph{size} bytes in length. It is the caller's responsibility to
|
|
make sure the region is free by calling {\tt check_region}, prior
|
|
to calling this routine.
|
|
|
|
\item[release_region]
|
|
\funcproto void release_region(unsigned port, unsigned size);
|
|
|
|
Free the I/O address space region starting at \emph{port} and
|
|
\emph{size} bytes in length, previously allocated by {\tt request_region}.
|
|
|
|
\item[add_wait_queue]
|
|
\funcproto void add_wait_queue(struct~wait_queue **q, struct~wait_queue *wait);
|
|
|
|
Add the wait element \emph{wait} to the wait queue \emph{q}.
|
|
|
|
\item[remove_wait_queue]
|
|
\funcproto void remove_wait_queue(struct~wait_queue **q,
|
|
struct~wait_queue *wait);
|
|
|
|
Remove the wait element \emph{wait} from the wait queue \emph{q}.
|
|
|
|
\item[down]
|
|
\funcproto void down(struct~semaphore *sem);
|
|
|
|
Perform a down operation on the semaphore \emph{sem}. The caller blocks if
|
|
the value of the semaphore is less than or equal to 0.
|
|
|
|
\item[sleep_on]
|
|
\funcproto void sleep_on(struct~wait_queue **q, int interruptible);
|
|
|
|
Add the caller to the wait queue \emph{q}, and block it.
|
|
If \emph{interruptible} flag is non-zero, the caller can be woken up from
|
|
its sleep by a signal.
|
|
|
|
\item[wake_up]
|
|
\funcproto void wake_up(struct~wait_queue **q);
|
|
|
|
Wake up anyone waiting on the wait queue \emph{q}.
|
|
|
|
\item[wait_on_buffer]
|
|
\funcproto void wait_on_buffer(struct~buffer_head *bh);
|
|
|
|
Put the caller to sleep, waiting on the buffer \emph{bh}.
|
|
Called by drivers to wait for I/O completion on the buffer.
|
|
|
|
\item[schedule]
|
|
\funcproto void schedule(void);
|
|
|
|
Call the scheduler to pick the next task to run.
|
|
|
|
\item[add_timer]
|
|
\funcproto void add_timer(struct~timer_list *timer);
|
|
|
|
Schedule a time out. The length of the time out and function to be called
|
|
on timer expiry are specified in \emph{timer}.
|
|
|
|
\item[del_timer]
|
|
\funcproto int del_timer(struct~timer_list *timer);
|
|
|
|
Cancel the time out \emph{timer}.
|
|
\end{icsymlist}
|
|
|
|
|
|
\subsection{Directory Structure}
|
|
|
|
The {\tt linux} subdirectory in the \oskit\ source tree
|
|
is organized as follows.
|
|
The top-level {\tt linux/dev} directory
|
|
contains all the glue code implemented by the Flux project
|
|
to squash the Linux drivers into the \oskit{} driver framework.
|
|
{\tt linux/fs} contains our glue for Linux filesystems,
|
|
and {\tt linux/shared} contains glue used by both components.
|
|
In general, everything \emph{except} the code in the {\tt linux/src} directory
|
|
was written by us, whereas everything under {\tt linux/src}
|
|
comes verbatim from Linux.
|
|
Each of the subdirectories of {\tt linux/src}
|
|
corresponds to the identically named subdirectories
|
|
of in the Linux kernel source tree.
|
|
|
|
Of course, there are a few necessary deviations from this rule:
|
|
a few of the Linux header and source files are slightly modified,
|
|
and a few of the Linux header files (but no source files)
|
|
were completely replaced.
|
|
The header files that were heavily modified include:
|
|
|
|
\begin{csymlist}
|
|
\item[linux/src/include/linux/sched.h] Linux task and scheduling declarations
|
|
\end{csymlist}
|
|
|
|
|
|
\section{Block device drivers}
|
|
|
|
\begin{table}
|
|
\begin{tabular}[c]{|l|l||c|c|c|c|c|}
|
|
\hline
|
|
Name & Description & $V=P$
|
|
& {\tt jiffies}
|
|
& {\tt P+Y}
|
|
& {\tt current}
|
|
& \\
|
|
\hline
|
|
\hline
|
|
cmd640.c & CMD640 IDE Chipset & & & & & \\\hline
|
|
floppy & Floppy drive &*&*&*&*& \\\hline
|
|
ide-cd.c & IDE CDROM & &*&*&*& \\\hline
|
|
ide.c & IDE Disk & & & & & \\\hline
|
|
rz1000.c & RZ1000 IDE Chipset & & & & & \\\hline
|
|
sd.c & SCSI disk & &*& & & \\\hline
|
|
sr.c & SCSI CDROM & & & & & \\\hline
|
|
triton.c & Triton IDE Chipset &*& & & & \\\hline
|
|
\end{tabular}
|
|
\label{linux-block-drivers}
|
|
\caption{Linux block device drivers}
|
|
\end{table}
|
|
|
|
\section{Network drivers}
|
|
|
|
Things drivers may want to do
|
|
that make emulation difficult:
|
|
\begin{itemize}
|
|
\item Call the 16-bit BIOS.
|
|
\item Use the system DMA controller.
|
|
\item Assume kernel virtual addresses are equivalent to physical addresses.
|
|
\item Assume kernel virtual addresses can be mapped to physical addresses
|
|
merely by adding a constant offset.
|
|
\item Implement timeouts by busy-waiting on a global clock-tick counter.
|
|
\item Busy-wait for interrupts.
|
|
XXX This means that the OS \emph{must} allow interrupts
|
|
during execution of process-level driver code,
|
|
and not just when all process-level activity is blocked.
|
|
\end{itemize}
|
|
|
|
\begin{table}
|
|
\begin{tabular}[c]{|l|l||c|c|c|c|c|}
|
|
\hline
|
|
Name & Description & $V=P$
|
|
& {\tt jiffies}
|
|
& {\tt P+Y}
|
|
& {\tt current}
|
|
& \\
|
|
\hline
|
|
\hline
|
|
3c501.c & 3Com 3c501 ethernet & &*& & & \\\hline
|
|
3c503.c & NS8390 ethernet & &*& & & \\\hline
|
|
3c505.c & 3Com Etherlink Plus (3C505) & &*& & & \\\hline
|
|
3c507.c & 3Com EtherLink16 & &*& & & \\\hline
|
|
3c509.c & 3c509 EtherLink3 ethernet & &*& & & \\\hline
|
|
3c59x.c & 3Com 3c590/3c595 "Vortex" & &*& & & \\\hline
|
|
ac3200.c & Ansel Comm. EISA ethernet & &*& & & \\\hline
|
|
apricot.c & Apricot &*&*& & & \\\hline
|
|
at1700.c & Allied Telesis AT1700 & &*& & & \\\hline
|
|
atp.c & Attached (pocket) ethernet & &*& & & \\\hline
|
|
de4x5.c & DEC DE425/434/435/500 & &*& & & \\\hline
|
|
de600.c & D-link DE-600 & &*& & & \\\hline
|
|
de620.c & D-link DE-620 & &*& & & \\\hline
|
|
depca.c & DEC DEPCA \& EtherWORKS & &*& & & \\\hline
|
|
e2100.c & Cabletron E2100 & &*& & & \\\hline
|
|
eepro.c & Intel EtherExpress Pro/10 & &*& & & \\\hline
|
|
eexpress.c & Intel EtherExpress & &*& & & \\\hline
|
|
eth16i.c & ICL EtherTeak 16i \& 32 & &*& & & \\\hline
|
|
ewrk3.c & DEC EtherWORKS 3 & &*& & & \\\hline
|
|
hp-plus.c & HP PCLAN/plus & &*& & & \\\hline
|
|
hp.c & HP LAN & &*& & & \\\hline
|
|
hp100.c & HP10/100VG ANY LAN & &*& & & \\\hline
|
|
lance.c & AMD LANCE &*&*& & & \\\hline
|
|
ne.c & Novell NE2000 & &*& & & \\\hline
|
|
ni52.c & NI5210 (i82586 chip) & &*& & & \\\hline
|
|
ni65.c & NI6510 (am7990 `lance' chip) &*&*& & & \\\hline
|
|
seeq8005.c & SEEQ 8005 & &*& & & \\\hline
|
|
sk_g16.c & Schneider \& Koch G16 & &*& & & \\\hline
|
|
smc-ultra.c & SMC Ultra & &*& & & \\\hline
|
|
tulip.c & DEC 21040 &*&*& & & \\\hline
|
|
wavelan.c & AT\&T GIS (NCR) WaveLAN & &*& & & \\\hline
|
|
wd.c & Western Digital WD80x3 & &*& & & \\\hline
|
|
znet.c & Zenith Z-Note & &*& & & \\\hline
|
|
\end{tabular}
|
|
\label{linux-net-drivers}
|
|
\caption{Linux network drivers}
|
|
\end{table}
|
|
|
|
\section{SCSI drivers}
|
|
|
|
The Linux SCSI driver set includes
|
|
both the low-level SCSI host adapter drivers
|
|
and the high-level SCSI drivers for generic SCSI disks, tapes, etc.
|
|
|
|
|
|
\begin{table}
|
|
{\small
|
|
\begin{tabular}[c]{|l|l||c|c|c|c|c|}
|
|
\hline
|
|
Name & Description & $V=P$
|
|
& {\tt jiffies}
|
|
& {\tt P+Y}
|
|
& {\tt current}
|
|
& \\
|
|
\hline
|
|
\hline
|
|
53c7,8xx.c & NCR 53C7x0, 53C8x0 &*&*& & & \\\hline
|
|
AM53C974.c & AM53/79C974 (PCscsi) &*& & & & \\\hline
|
|
BusLogic.c & BusLogic MultiMaster adapters &*&*& & & \\\hline
|
|
NCR53c406a.c & NCR53c406a &*&*& & & \\\hline
|
|
advansys.c & AdvanSys SCSI Adapters &*&*& & & \\\hline
|
|
aha152x.c & Adaptec AHA-152x & &*& & & \\\hline
|
|
aha1542.c & Adaptec AHA-1542 &*&*& & & \\\hline
|
|
aha1740.c & Adaptec AHA-1740 &*& & & & \\\hline
|
|
aic7xxx.c & Adaptec AIC7xxx &*&*& & & \\\hline
|
|
eata.c & EATA 2.x DMA host adapters & &*& & & \\\hline
|
|
eata_dma.c & EATA/DMA host adapters &*&*& & & \\\hline
|
|
eata_pio.c & EATA/PIO host adapters & &*& & & \\\hline
|
|
fdomain.c & Future Domain TMC-16x0 & &*& & & \\\hline
|
|
in2000.c & Always IN 2000 & &*& & & \\\hline
|
|
NCR5380.c & Generic NCR5380 &*&*&*& & \\\hline
|
|
pas16.c & Pro Audio Spectrum/Studio 16 & & & & & \\\hline
|
|
qlogic.c & Qlogic FAS408 & &*& & & \\\hline
|
|
scsi.c & SCSI middle layer &*&*&*&*& \\\hline
|
|
scsi_debug.c & SCSI debug layer & &*& & & \\\hline
|
|
seagate.c & ST01,ST02, TMC-885 & &*& & & \\\hline
|
|
t128.c & Trantor T128/128F/228 & & & & & \\\hline
|
|
u14-34f.c & UltraStor 14F/34F &*&*& & & \\\hline
|
|
ultrastor.c & UltraStor 14F/24F/34F &*& & & & \\\hline
|
|
wd7000.c & WD-7000 &*&*& & & \\\hline
|
|
\end{tabular}
|
|
\label{linux-scsi-drivers}
|
|
\caption{Linux SCSI drivers}
|
|
}
|
|
\end{table}
|