File: linux-dev.tex

package info (click to toggle)
oskit 0.97.20000202-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 58,008 kB
  • ctags: 172,612
  • sloc: ansic: 832,827; asm: 7,640; sh: 3,920; yacc: 3,664; perl: 1,457; lex: 427; makefile: 337; csh: 141; awk: 78
file content (909 lines) | stat: -rw-r--r-- 33,205 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
%
% Copyright (c) 1996-1998 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
{\em 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.0.29, 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 {\em 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.html\#SOSKIT}%
		  {http://www.cs.utah.edu/flux/papers.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 {\em 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 {\em 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 {\em major}.
When an access is made to a device with the specified major number,
the kernel accesses the driver through the operations vector {\em 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 {\em 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 {\em size} bytes in
length and associate it with device {\em dev}, and block number {\em block}.

\item[brelse]
\funcproto void brelse(struct buffer_head *bh);

This function frees the buffer {\em 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 {\em size} bytes in length, and fills
it with data from device {\em dev}, starting at block number {\em 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 {\em count}
bytes of data to the device specified by {\em i_rdev} field of
{\em inode}, starting at byte offset specified by {\em f_pos} of
{\em file}, from the buffer {\em 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 {\em count}
bytes of data from the device specified by {\em i_rdev} field of
{\em inode}, starting at byte offset specified by {\em f_pos} field of
{\em file}, into the buffer {\em 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 {\em dev}.  It does so by invoking the
{\em check_media_change} function in the driver's file operations
vector.  If a change has occurred, it calls the driver's {\em 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 {\em 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 {\em drq} previously
allocated by {\tt request_dma}.

\item[disable_irq]
\funcproto void disable_irq(unsigned irq);

This function masks the interrupt request line {\em irq} at the
interrupt controller.

\item[enable_irq]
\funcproto void enable_irq(unsigned irq);

This function unmasks the interrupt request line {\em 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 {\em irq}, and
attach the interrupt handler {\em 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 {\em irq}, previously
allocated by {\tt request_irq}.

\item[kmalloc]
\funcproto void *kmalloc(unsigned~int size, int priority);

This function allocates {\em size} bytes memory.
The {\em 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 {\em p} previously allocated by
{\tt kmalloc}.

\item[vmalloc]
\funcproto void *vmalloc(unsigned long size);

This function allocates {\em 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 {\em port} and
{\em 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 {\em port} and
{\em 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 {\em port} and
{\em size} bytes in length, previously allocated by {\tt request_region}.

\item[add_wait_queue]
\funcproto void add_wait_queue(struct wait_queue **q, stuct wait_queue *wait);

Add the wait element {\em wait} to the wait queue {\em q}.

\item[remove_wait_queue]
\funcproto void remove_wait_queue(struct wait_queue **q,
				  struct wait_queue *wait);

Remove the wait element {\em wait} from the wait queue {\em q}.

\item[down]
\funcproto void down(struct semaphore *sem);

Perform a down operation on the semaphore {\em 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 {\em q}, and block it.
If {\em 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 {\em q}.

\item[wait_on_buffer]
\funcproto void wait_on_buffer(struct buffer_head *bh);

Put the caller to sleep, waiting on the buffer {\em 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 {\em timer}.

\item[del_timer]
\funcproto int del_timer(struct timer_list *timer);

Cancel the time out {\em 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 {\em 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}