Device Drivers in Xenix
Nick Vasilatos
nick at harvard.UUCP
Tue Apr 1 17:40:16 AEST 1986
> I am trying to write a device driver for SCO's Xenix SYSTEM V release 2
Assorted lore --
A paddr_t is a (long) physical address (intended for real, live,
on the bus addresses), see <sys/types.h>.
The kernel, data first, is (or was, last I looked) loaded at 0x4000,
so add 0x4000 to a kernel logical address to get a physical address.
Far pointers are 32 bit pointers, the high word of which is an offset
into either a particular local, or the system global descriptor table
(LDT or GDT as it were; physical addresses are not directly meaningful
to the 286 -- it operates on 16 bit address offsets interpreted
relative to base addresses determined from the contents of it's
various segment registers vis a vis these tables).
To set up a far pointer for accessing physical addresses
in a device driver:
Call (unsigned) dscralloc() to obtain a gdt descriptor
for exclusive use by your driver (a compile time configurable
number of which are reserved for such use). It returns a
``selector'' which is the (aforementioned) offset of the
descriptor in the gdt.
Fill in the elements (address, limit (segment size - 1)
and protection) of the descriptor. Use:
mmudescr((unsigned) selector, (paddr_t) address,
(unsigned) limit, (char) (access = DSA_DATA, from
<sys/mmu.h>));
The limit should be the size of the object you are trying
access. The hardware will favour you with a general
protection trap if you exceed that limit (ie. miss) if you
set it correctly.
Make a far pointer out of the selector and a zero offset
with a macro provided in <sys/param.h>:
char far *dp = sotofar(selector,0);
In as much as the 286 has a ruthlessly efficient string move,
you probably don't want to code loops around far pointer
assignments. For such as that use:
copyseg((paddr_t) source, (paddr_t) dest, (unsigned) cnt);
They are otherwise the right way to poke around the address space.
If the device you are trying to drive's privies are memory
mapped, you are in business. If they are I/O mapped (attached to
the 286's seperate, 64k i/o bus) you are stuck with in and
out instructions (accessed via in() and out() calls and i/o space
relative 16 bit offsets).
The drill in general is to create a C structure describing your
device registers, data buffers, or what have you that you're trying
to access and use it's size to determine the segment limit and
reference it to determine offsets, however you must apply them.
The initialization handler of your driver is the apropo
place to undertake descriptor allocation and setup.
Physio disallows i/o into text or unallocated user memory
(reasonable) -- a buffer that is mapped into a single data
segment must be referenced by base and count in u. It also
disallows odd addresses and counts. It also insists on even
block multiples unless the BTAPE flag in the buffer header
you're passing it is set.
More information about the Comp.unix.wizards
mailing list