mmap(9E)
NAME
mmap - check virtual mapping for memory mapped device
SYNOPSIS
#include <sys/types.h>
#include <sys/cred.h>
#include <sys/mman.h>
#include <sys/ddi.h>
int prefixmmap(dev_t dev, off_t off, int prot);
INTERFACE LEVEL
This interface is obsolete. devmap(9E) should be used
instead.
PARAMETERS
dev Device whose memory is to be mapped.
off Offset within device memory at which mapping begins.
prot A bit field that specifies the protections this page
of memory will receive. Possible settings are:
PROT_READ
Read access will be granted.
PROT_WRITE
Write access will be granted.
PROT_EXEC
Execute access will be granted.
PROT_USER
User-level access will be granted.
PROT_ALL
All access will be granted.
DESCRIPTION
Future releases of Solaris will provide this function for
binary and source compatibility. However, for increased
functionality, use devmap(9E) instead. See devmap(9E) for
details.
The mmap() entry point is a required entry point for charac-
ter drivers supporting memory-mapped devices. A memory
mapped device has memory that can be mapped into a process's
address space. The mmap(2) system call, when applied to a
character special file, allows this device memory to be
mapped into user space for direct access by the user appli-
cation.
The mmap() entry point is called as a result of an mmap(2)
system call, and also as a result of a page fault. mmap() is
called to translate the offset off in device memory to the
corresponding physical page frame number.
The mmap() entry point checks if the offset off is within
the range of pages exported by the device. For example, a
device that has 512 bytes of memory that can be mapped into
user space should not support offsets greater than 512. If
the offset does not exist, then -1 is returned. If the
offset does exist, mmap() returns the value returned by
hat_getkpfnum(9F) for the physical page in device memory
containing the offset off.
hat_getkpfnum(9F) accepts a kernel virtual address as an
argument. A kernel virtual address can be obtained by cal-
ling ddi_regs_map_setup(9F) in the driver's attach(9E) rou-
tine. The corresponding
ddi_regs_map_free(9F) call can be made in the driver's
detach(9E) routine. Refer to The mmap() Entry Point below
for more information.
mmap() should only be supported for memory-mapped devices.
See the segmap(9E) and ddi_mapdev(9F) reference pages for
further information on memory-mapped device drivers.
If a device driver shares data structures with the applica-
tion, for example through exported kernel memory, and the
driver gets recompiled for a 64-bit kernel but the applica-
tion remains 32-bit, the binary layout of any data struc-
tures will be incompatible if they contain longs or
pointers. The driver needs to know whether there is a model
mismatch between the current thread and the kernel and take
necessary action. ddi_mmap_get_model(9F) can be use to get
the C Language Type Model which the current thread expects.
In combination with ddi_model_convert_from(9F) the driver
can determine whether there is a data model mismatch between
the current thread and the device driver. The device driver
might have to adjust the shape of data structures before
exporting them to a user thread which supports a different
data model. See ddi_mmap_get_model(9F) for an example.
RETURN VALUES
If the protection and offset are valid for the device, the
driver should return the value returned by
hat_getkpfnum(9F), for the page at offset off in the
device's memory. If not, -1 should be returned.
EXAMPLES
Example 1: The mmap() Entry Point
The following is an example of the mmap() entry point. If
offset off is valid, hat_getkpfnum(9F) is called to obtain
the page frame number corresponding to this offset in the
device's memory. In this example, xsp->regp->csr is a kernel
virtual address which maps to device memory.
ddi_regs_map_setup(9F) can be used to obtain this address.
For example, ddi_regs_map_setup(9F) can be called in the
driver's attach(9E) routine. The resulting kernel virtual
address is stored in the xxstate structure, which is acces-
sible from the driver's mmap() entry point. See
ddi_soft_state(9F). The corresponding ddi_regs_map_free(9F)
call can be made in the driver's detach(9E) routine.
struct reg {
uint8_t csr;
uint8_t data;
};
struct xxstate {
...
struct reg *regp
...
};
struct xxstate *xsp;
...
static int
xxmmap(dev_t dev, off_t off, int prot)
{
int instance;
struct xxstate *xsp;
/* No write access */
if (prot & PROT_WRITE)
return (-1);
instance = getminor(dev);
xsp = ddi_get_soft_state(statep, instance);
if (xsp == NULL)
return (-1);
/* check for a valid offset */
if ( off is invalid )
return (-1);
return (hat_getkpfnum (xsp->regp->csr + off));
}
ATTRIBUTES
See attributes(5) for a description of the following attri-
butes:
____________________________________________________________
| ATTRIBUTE TYPE | ATTRIBUTE VALUE |
|_____________________________|_____________________________|
| Stability Level | Obsolete |
|_____________________________|_____________________________|
SEE ALSO
mmap(2), attributes(5), attach(9E), detach(9E), devmap(9E),
segmap(9E), ddi_btop(9F), ddi_get_soft_state(9F),
ddi_mmap_get_model(9F), ddi_model_convert_from(9F),
ddi_regs_map_free(9F), ddi_regs_map_setup(9F),
ddi_soft_state(9F), devmap_setup(9F), getminor(9F),
hat_getkpfnum(9F)
Writing Device Drivers
NOTES
For some devices, mapping device memory in the driver's
attach(9E) routine and unmapping device memory in the
driver's detach(9E) routine is a sizeable drain on system
resources. This is especially true for devices with a large
amount of physical address space.
One alternative is to create a mapping for only the first
page of device memory in attach(9E). If the device memory is
contiguous, a kernel page frame number may be obtained by
calling hat_getkpfnum(9F) with the kernel virtual address of
the first page of device memory and adding the desired page
offset to the result. The page offset may be obtained by
converting the byte offset off to pages. See ddi_btop(9F).
Another alternative is to call ddi_regs_map_setup(9F) and
ddi_regs_map_free(9F) in mmap(). These function calls would
bracket the call to hat_getkpfnum(9F).
However, note that the above alternatives may not work in
all cases. The existence of intermediate nexus devices with
memory management unit translation resources that are not
locked down may cause unexpected and undefined behavior.
Man(1) output converted with
man2html