home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
mmap-2.2.3
/
part02
< prev
next >
Wrap
Text File
|
1993-12-27
|
40KB
|
1,211 lines
Newsgroups: comp.sources.unix
From: thomas@aeon.in-berlin.de (Thomas Wolfram)
Subject: v27i194: mmap-2.2.3 - A SVR3.2 Memory Mapped I/O Driver v2.2.3, Part02/02
References: <1.757030996.11792@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: thomas@aeon.in-berlin.de (Thomas Wolfram)
Posting-Number: Volume 27, Issue 194
Archive-Name: mmap-2.2.3/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 2)."
# Contents: mmap-2.2.3/mmap.7 mmap-2.2.3/mmap.c mmap-2.2.3/mmap.man
# Wrapped by thomas@aeon on Mon Dec 27 21:18:39 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mmap-2.2.3/mmap.7' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mmap-2.2.3/mmap.7'\"
else
echo shar: Extracting \"'mmap-2.2.3/mmap.7'\" \(12533 characters\)
sed "s/^X//" >'mmap-2.2.3/mmap.7' <<'END_OF_FILE'
X
X
X
X mmap(7L) 386/ix mmap(7L)
X
X
X
X NAME
X mmap - MMMMMMMMAAAAPPPP ioctl commands (memory mapped I/O support)
X
X SYNOPSIS
X #include <sys/types.h>
X #ifndef SCO
X #include <sys/at_ansi.h>
X #include <sys/kd.h>
X #else
X #include <sys/vtkd.h>
X #endif
X #include <sys/sysmacros.h>
X #include <sys/immu.h>
X #include <sys/region.h>
X #include <sys/mmap.h>
X
X int ioctl(fildes, command, arg);
X int fildes, command;
X
X DESCRIPTION
X _M_M_A_P is a pseudo device driver which provides memory mapped
X I/O for user processes, i.e. direct mapping of physical
X memory ranges into the user's virtual address space for fast
X access. It is especially useful for accessing the linear
X frame buffers of certain graphic hardware from the user
X level.
X
X To executing the _M_M_A_P _i_o_c_t_l commands _f_i_l_d_e_s must be an open
X file descriptor [see _o_p_e_n(_2)] that refers to the special
X character device /_d_e_v/_m_m_a_p. The effective user ID of the
X calling process must be superuser.
X The driver uses shared memory type regions for mapping. So
X the maximum number of regions the driver can attach to a
X process is limited by the maximum number of shared memory
X regions which can be attached to the process [see _s_h_m_g_e_t(_2),
X _s_h_m_o_p(_2), _s_h_m_c_t_l(_2)]. This number is a tunable system param-
X eter (_S_H_M_S_E_G) [see _k_c_o_n_f_i_g(_1), _i_d_t_u_n_e(_1_M)].
X The number of regions which the driver is able to map
X system-wide (i.e. to all running processes) is limited too.
X This number is also a tunable system parameter (_N_M_M_A_P_R_E_G).
X
X Note, the _M_M_A_P driver grows the virtual address space of the
X calling process by itself. Allocating address space before
X with _m_a_l_l_o_c(_3) isn't necessary and will not work.
X The mapping regions allocated by the driver will always be
X sharable, never private to a process. Regions can be of type
X read/write or read/only. This depends from the _m_o_d_e
X /_d_e_v/_m_m_a_p is opened [see _o_p_e_n(_2)]. Once a region is allo-
X cated and mapped to a process it will normally remain in the
X system (until reboot) even if the last process which pointed
X at it detaches it from its address space. (This is not much
X waste since the _M_M_A_P driver allocates no physical pages for
X the mapping region.) But with the _U_N_M_A_P_R_M ioctl removing
X
X
X Rev. 2.2.3, 22 November 1993 Page 1
X
X
X
X
X
X
X mmap(7L) 386/ix mmap(7L)
X
X
X
X after unmapping can be requested [see below and _m_m_a_p_r_m(_1_L)].
X If a process wants to map in the same memory range like
X another one (e.g. if it's the same program which is running
X again) it will be attached with the already existing region
X by the driver. Same applies if the processes which requests
X the same mapping are running simultaneously.
X
X Ioctl Calls
X The following ioctl commands can be used:
X
X MMMMAAAAPPPP
X This call maps physical memory into the virtual address
X space of the user process. The following structure,
X defined in <sys/kd.h> [see _d_i_s_p_l_a_y(_7)], is pointed to by
X the argument _a_r_g to the ioctl:
X
X struct kd_memloc {
X char *vaddr; /* virtual address to map to */
X char *physaddr; /* physical address to map from */
X long length; /* size in bytes to map */
X long ioflg; /* not used by the _M_M_A_P driver */
X };
X
X The _v_a_d_d_r argument is the linear address in the process
X where the physical memory range will appear. This address
X must be on a boundary specified by the machine dependant
X constant _M_M_A_P_L_B_A, defined in <sys/mmap.h>. If _v_a_d_d_r is
X equal to zero the address is selected by the driver
X itself.
X The _p_h_y_s_a_d_d_r argument is the physical address of the
X memory range that will be mapped in. It must be on a page
X boundary.
X The _l_e_n_g_t_h argument is the size of the memory range that
X will be mapped in. It will be rounded up to a multiple of
X the size of a page by the driver.
X On success the ioctl will return the virtual address where
X the memory is mapped in. It will fail if one or more of
X the following is true:
X
X [EPERM] The effective user ID of the calling pro-
X cess is not superuser.
X
X [EFAULT] The user address pointed to by _a_r_g is
X illegal.
X
X [EINVAL] The _v_a_d_d_r argument is not equal to zero,
X and the value is an illegal address (not
X on a MMAPLBA boundary, already used in
X the process or not below _M_A_X_U_V_A_D_R, as
X defined in <sys/immu.h>).
X
X [EINVAL] The _p_h_y_s_a_d_d_r argument is not on a page
X boundary.
X
X
X Rev. 2.2.3, 22 November 1993 Page 2
X
X
X
X
X
X
X mmap(7L) 386/ix mmap(7L)
X
X
X
X [ENOMEM] The _v_a_d_d_r argument is equal to zero and
X the driver is not able to find a proper
X region in the user's address space where
X the memory range would fit in.
X
X [ENOMEM] The size of the user's virtual address
X space would exceed the system-imposed
X limit.
X
X [ENOMEM] Not enough system internal space avail-
X able to grow the user's virtual address
X space.
X
X [EMFILE] The number of shared memory segments
X attached to the calling process would
X exceed the system-imposed limit.
X
X [EMFILE] The number of all memory mapped regions
X in the system would exceed the driver-
X imposed limit.
X
X UUUUNNNNMMMMAAAAPPPP
X This call unmaps previously mapped physical memory from
X the calling process. The argument _a_r_g to the ioctl must
X be the virtual address as returned by the previous _M_A_P
X ioctl.
X It will fail if one or more of the following is true:
X
X [EPERM] The effective user ID of the calling pro-
X cess is not superuser.
X
X [EINVAL] If _a_r_g is not the start address of a
X region mapped by the driver to the cal-
X ling process.
X
X UUUUNNNNMMMMAAAAPPPPRRRRMMMM
X Same like _U_N_M_A_P but removes the concerning region from the
X systems internal list, if no other process is still using
X it [see _m_m_a_p_r_m(_1_L)].
X
X GGGGEEEETTTTNNNNMMMMMMMMRRRREEEEGGGG
X This call returns the number of the memory mapped I/O
X regions which exists currently in the system [_s_e_e
X _m_m_a_p_s_t_a_t(_1_L)]. It requires no argument. It will fail if
X one or more of the following is true:
X
X [EPERM] The effective user ID of the calling pro-
X cess is not superuser.
X
X GGGGEEEETTTTMMMMMMMMRRRREEEEGGGG
X This call returns the current status of the _M_M_A_P driver.
X The argument _a_r_g must be a pointer to an array of elements
X of the following type (defined in <sys/mmap.h>):
X
X
X Rev. 2.2.3, 22 November 1993 Page 3
X
X
X
X
X
X
X mmap(7L) 386/ix mmap(7L)
X
X
X
X typedef struct mmapinfo {
X paddr_t physaddr; /* physical address */
X long length; /* size in bytes */
X short refcnt; /* number of users */
X /* pointing currently at this region */
X } mmapinfo_t;
X
X which is filled by the driver for every region currently
X exists. The array must have as much elements as the
X number returned by the _G_E_T_N_M_M_R_E_G ioctl states [see
X _m_m_a_p_s_t_a_t(_1_L)]. The command will fail if one or more of
X the following is true:
X
X [EPERM] The effective user ID of the calling pro-
X cess is not superuser.
X
X [EFAULT] The user address pointed to by _a_r_g is
X illegal.
X
X
X
X GGGGEEEETTTTVVVVEEEERRRRSSSSIIIIOOOONNNN
X Returns version number of driver, e.g. version 2.2.1 would
X be returned as 0x0221.
X
X FILES
X /_d_e_v/_m_m_a_p
X Character device interface to the driver.
X
X SEE ALSO
X open(2), ioctl(2), display(7), shmget(2), shmop(2),
X shmctl(2), kconfig(1), idtune(1M), intro(2), mmapstat(1L),
X mmaprm(1L).
X
X DIAGNOSTICS
X Upon sucessful completion, the return value is as follows:
X
X The _M_A_P ioctl returns the user's address where the phy-
X sical memory is mapped in.
X
X The _U_N_M_A_P and _U_N_M_A_P_R_M ioctl's return a value of 0.
X
X The _G_E_T_N_M_M_R_E_G ioctl returns the number of memory mapped
X I/O regions which exists currently in the system.
X
X The _G_E_T_M_M_R_E_G ioctl returns a value of 0.
X
X The _G_E_T_V_E_R_S_I_O_N ioctl returns the version number.
X
X Otherwise, a value of -1 is returned, and _e_r_r_n_o [see
X _i_n_t_r_o(_2)] is set to indicate the error.
X
X BUGS
X
X
X Rev. 2.2.3, 22 November 1993 Page 4
X
X
X
X
X
X
X mmap(7L) 386/ix mmap(7L)
X
X
X
X Please report bugs to: wwwwoooollllffff@@@@pppprrrrzzzz....ttttuuuu----bbbbeeeerrrrlllliiiinnnn....ddddeeee or
X tttthhhhoooommmmaaaassss@@@@aaaaeeeeoooonnnn....iiiinnnn----bbbbeeeerrrrlllliiiinnnn....ddddeeee.
X
X COPYING
X Copyright (c) 1993 Thomas Wolfram
X
X AUTHOR
X Thomas Wolfram
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X Rev. 2.2.3, 22 November 1993 Page 5
X
X
X
END_OF_FILE
echo shar: 599 control characters may be missing from \"'mmap-2.2.3/mmap.7'\"
if test 12533 -ne `wc -c <'mmap-2.2.3/mmap.7'`; then
echo shar: \"'mmap-2.2.3/mmap.7'\" unpacked with wrong size!
fi
# end of 'mmap-2.2.3/mmap.7'
fi
if test -f 'mmap-2.2.3/mmap.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mmap-2.2.3/mmap.c'\"
else
echo shar: Extracting \"'mmap-2.2.3/mmap.c'\" \(15554 characters\)
sed "s/^X//" >'mmap-2.2.3/mmap.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1993 by Thomas Wolfram, Berlin, Germany.
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of Thomas Wolfram be used in
X * advertising or publicity pertaining to distribution of the software without
X * specific, written prior permission. Thomas Wolfram makes no
X * representations about the suitability of this software for any purpose.
X * It is provided "as is" without express or implied warranty.
X *
X * THOMAS WOLFRAM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
X * EVENT SHALL THOMAS WOLFRAM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
X * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
X * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
X * PERFORMANCE OF THIS SOFTWARE.
X *
X * Author: Thomas Wolfram, thomas@aeon.in-berlin.de, wolf@prz.tu-berlin.de
X */
X
X#if !defined (M_I286)
X#ident "@(#)mmap.c - MMAP v2.2.3, Copyright (c) Thomas Wolfram 1993"
X#endif
X
X#define MMAP_MAJ 2
X#define MMAP_MIN 2
X#define MMAP_PL 3
X#define MMAPVERSION MMAP_MAJ*256 + MMAP_MIN*16 + MMAP_PL
X
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/param.h>
X#include <sys/dir.h>
X#include <sys/signal.h>
X#include <sys/user.h>
X
X#include <sys/errno.h>
X
X#ifndef SCO
X#include <sys/at_ansi.h> /* get typedef needed in kd.h */
X#include <sys/kd.h> /* get struct kd_memloc */
X#else
X#include <sys/vtkd.h>
X#endif
X
X#include <sys/sysmacros.h>
X#include <sys/immu.h>
X#include <sys/region.h>
X#include <sys/proc.h>
X
X#include <sys/ipc.h> /* get typedef needed in shm.h */
X#include <sys/shm.h> /* get shminfo */
X
X#include <sys/mmap.h>
X
X/* For SCO, page locking is done not per-page table entry, but
X * per-pfdat.
X */
X#ifndef PG_LOCK
X#define PG_LOCK 0
X#endif
X
X#define False 0
X#define True 1
X
X/* Move address x to previous and next low boundary address.
X */
X#define prev_ba(x) (caddr_t)((uint)x & ~(MMAPLBA-1))
X#define next_ba(x) (caddr_t)(((uint)x + MMAPLBA) & ~(MMAPLBA-1))
X
X/* Nowhere else declared. */
Xextern dbd_t *finddbd();
X
X/* System's shared memory info structure.
X */
Xextern struct shminfo shminfo;
X
X/* Physical addresses of I/O regions memory mapped by the driver.
X * Defined in space.c.
X */
Xextern mmapreg_t mmapreg[];
X
X/* Size of this array for use by the driver. Defined in space.c.
X */
Xextern uint nmmapreg;
X
Xint mmapinit();
Xint mmapioctl();
X
Xstatic caddr_t FindVirtAddr();
X
X
X/* Number of I/O regions memory mapped currently by the driver. */
Xstatic map_cnt = 0;
X
Xstatic struct kd_memloc memDesc;
Xstatic mmapinfo_t ibuf;
X
X
Xint mmapinit()
X{
X printf("Memory Mapped I/O Driver v%d.%d.%d installed.\n",
X MMAP_MAJ, MMAP_MIN, MMAP_PL);
X printf("Copyright (c) 1993 Thomas Wolfram\n\n");
X
X}
X
Xint mmapioctl(dev, cmd, arg, mode)
X int dev;
X int cmd;
X int arg;
X int mode;
X{
X /* Don't put this much variables at the kernel stack. Although it
X * wouldn't matter, probably...
X */
X static reg_t *Reg_p;
X static preg_t *PReg_p;
X static pde_t *pte; /* page table entry */
X static dbd_t *dbdte; /* disk block descriptor entry */
X static unsigned char accmode;
X static int FreeReg;
X register uint i, off;
X register paddr_t pmem;
X
X
X /* Only superuser is allowed to do that. U.u_error is set to
X * EPERM if not superuser.
X */
X if(!suser())
X return;
X
X /* Default for unmapping is don't freeing the region */
X FreeReg = False;
X
X switch(cmd) {
X
X /* Map physical memory into process address space.
X */
X case MAP:
X
X /* Get the memory description block from user space.
X */
X if(copyin((caddr_t)arg, &memDesc, sizeof(memDesc)) == -1) {
X u.u_error = EFAULT;
X break;
X }
X
X /* Physical address must be page aligned.
X */
X if(poff(memDesc.physaddr) != 0) {
X u.u_error = EINVAL;
X break;
X }
X
X /* Check whether we already reached the limit of
X * attachable shared memory regions of this process.
X */
X if(!(u.u_nshmseg < shminfo.shmseg)) {
X u.u_error = EMFILE;
X break;
X }
X
X /* If no mapping address given by the user try to find one.
X */
X if(memDesc.vaddr == (caddr_t)0) {
X if((memDesc.vaddr = FindVirtAddr(memDesc.length)) == NULL) {
X u.u_error = ENOMEM;
X break;
X }
X }
X
X /* Check whether this physical range is already mapped to
X * a region. If so use it and don't allocate a new region.
X */
X Reg_p = NULL;
X for(i = 0; i < map_cnt; i++) {
X if((paddr_t)memDesc.physaddr == mmapreg[i].physaddr &&
X btoc(memDesc.length) == mmapreg[i].Reg_p->r_pgsz) {
X Reg_p = mmapreg[i].Reg_p;
X break;
X }
X }
X
X
X if(Reg_p != NULL) {
X
X /* If we have still such a region lock it.
X */
X reglock(Reg_p);
X
X /* XXXX This is a ugly hack.
X * If our region isn't any longer referenced by a process
X * it's possible that vhand steals the page tables of our
X * region. Attaching such a region with swapped-out page
X * tables doesn't work, because the page directory entries
X * of the process get a present-bit set to 1 and valid re-
X * ferences to page tables but which contain entries of in-
X * valid non-present pages. And the related dbd tables still
X * contain the type DBD_IOMAP.
X * I.e. the effect is there won't occur a page fault to
X * read the swapped-out page tables in, as I expected. The
X * page fault will instead occur in the second level (i.e. in
X * the page tables) when attempting to read the non-present
X * pages from disk or elsewhere. The kernel will look in the
X * dbd table and find the type DBD_IOMAP, but which is invalid
X * for a non-present page. Hence it would panic then with:
X * "vfault - bad dbd_type".
X *
X * Also I have no idea how I could the swapped-out page tables
X * read in "by hand". The "pseudo page directory" of the re-
X * gion (addressed by Reg_p->r_list) contains obviously only
X * the base addresses and not the page state flags. Also
X * I don't know how to find the dbd's of the page table's
X * pages.
X *
X * Probably I did something wrong here. If you've an idea
X * please let me know. Thanks.
X *
X * Anyway, until then I simply throw away the region if
X * the page tables of it are swapped out and then I reallocate
X * the same region.
X */
X if(Reg_p->r_flags & RG_SWAP) {
X
X /* Freereg takes only effect if no users pointing
X * at it.
X */
X if(Reg_p->r_refcnt == 0) {
X Reg_p->r_flags &= ~RG_NOFREE;
X freereg(Reg_p);
X
X /* Free the old slot and force allocating a
X * new region.
X */
X for(i = i; i < map_cnt; i++)
X mmapreg[i] = mmapreg[i+1];
X map_cnt--;
X
X Reg_p = NULL;
X
X#ifdef DEBUG
X printf("MMAP: Info - reallocate region [a=0x%x, l=%dk]\n", memDesc.physaddr, memDesc.length/1024);
X#endif
X }
X else {
X /* I hope this point here will never be reached!
X * Or - better - page tables are read in correctly
X * by the system. So we don't panic in the hope
X * it works.
X */
X printf("MMAP: Warning - region [a=%x, l=%dk] still used but page tables are swapped out!\n", memDesc.physaddr, memDesc.length/1024);
X printf("MMAP: Cannot reallocate this region!\n");
X printf("MMAP: Please email Thomas Wolfram <thomas@aeon.in-berlin.de> or\n <wolf@prz.tu-berlin.de>. Thanks.\n");
X
X /* panic("MMAP: PANIC\n");
X */
X }
X }
X }
X
X
X /* If necessary allocate a new region, type is shared memory.
X */
X if(Reg_p == NULL) {
X
X /* Check whether we are at the limit of regions we can map.
X */
X if(map_cnt > nmmapreg) {
X u.u_error = EMFILE;
X break;
X }
X
X /* Allocate new region which will be locked.
X */
X if((Reg_p = allocreg(NULL, RT_SHMEM, 0)) == NULL)
X break;
X }
X
X
X /* If the region is already initialized, check whether it is
X * allowed to grow the virtuell address space of the process by
X * btoc(memDesc.length) pages, before attaching it.
X */
X
X if(Reg_p->r_pgsz > 0) {
X
X if(chkpgrowth(btoc(memDesc.length)) < 0) {
X regrele(Reg_p);
X u.u_error = ENOMEM;
X break;
X }
X }
X
X /* Attach region to process, R/O or R/W. Will fail if vaddr is
X * not a multiple of SHMLBA (= MMAPLBA, 4MB on a i386).
X */
X if(mode & FWRITE)
X accmode = SEG_RW;
X else
X accmode = SEG_RO;
X
X if((PReg_p = attachreg(Reg_p, &u, memDesc.vaddr, PT_SHMEM, accmode))
X == NULL) {
X
X /* If attaching failed and region is already initialized,
X * release it. Otherwise free it again.
X */
X if(Reg_p->r_pgsz > 0)
X regrele(Reg_p);
X else
X freereg(Reg_p);
X break;
X }
X
X
X /* If region is new allocated, grow region without allocating
X * swapable memory (DBD_NONE prevents decrementing of availsmem
X * and availrmem), i.e. allocate only page tables and dbd tables.
X * Then map the physical memory into it.
X * But check whether it is allowed to grow the virtuell address
X * space of the process by btoc(memDesc.length) pages before.
X */
X if(Reg_p->r_pgsz == 0) {
X
X if(chkpgrowth(btoc(memDesc.length)) < 0) {
X detachreg(PReg_p, &u);
X u.u_error = ENOMEM;
X break;
X }
X
X if(growreg(PReg_p, btoc(memDesc.length), DBD_NONE) < 0) {
X detachreg(PReg_p, &u);
X u.u_error = ENOMEM;
X break;
X }
X
X
X /* Map physical memory into virtuell address space of process,
X * i.e. modify page tables and dbd tables.
X * I could also use mappages() here, but so I don't have the
X * overhead of it and know what I do.
X *
X * Linear address:
X * +----------+----------+------------+
X * | ptnum | pnum | byte off. |
X * +----------+----------+------------+
X * 10 10 12
X */
X pmem = (paddr_t)memDesc.physaddr;
X
X for(off = 0; off < memDesc.length; off += NBPP) {
X
X pte = (pde_t *)((uint)Reg_p->r_list[ptnum(off)] & PG_ADDR)
X + pnum(off);
X pte->pgi.pg_pde = (pmem & PG_ADDR) |
X PG_LOCK | PTE_RW | PG_P;
X /*
X * SCO does page locking per-pfdat, not per-page table entry
X * according to SCO's <sys/immu.h>. Also pg_setlock(),
X * pg_clrlock(), and pg_islocked() are not macros, but
X * functions on SCO now. Assumed they changed not the
X * parameter of the original macro (I don't believe it,
X * would had a lot more changes in the kernel required...),
X * following would lock the page in core:
X#ifdef SCO
X pg_setlock(pte);
X#endif
X * It's uncommented because it's not tested yet.
X */
X
X dbdte = finddbd(Reg_p, pte);
X dbdte->dbd_type = DBD_IOMAP;
X
X /* Move to next physical page. */
X pmem += NBPP;
X }
X
X /* Region is initialized. Don't free region on last detach.
X */
X Reg_p->r_flags |= RG_DONE | RG_NOFREE;
X Reg_p->r_dbdnone = 0;
X
X mmapreg[map_cnt].physaddr = (paddr_t)memDesc.physaddr;
X mmapreg[map_cnt++].Reg_p = Reg_p;
X
X } /* Region size still zero */
X
X /* Increase number of attached shared memory regions.
X */
X u.u_nshmseg++;
X
X /* Only count up this to prevent swapping. Maybe it's not
X * necessary.
X */
X Reg_p->r_noswapcnt++;
X
X /* Release region and return.
X */
X regrele(Reg_p);
X u.u_rval1 = (int)memDesc.vaddr;
X break;
X
X
X /* Unmap region from physical address space and try to free
X * it.
X */
X case UNMAPRM:
X FreeReg = True;
X
X /* Unmap region from physical address space.
X */
X case UNMAP:
X
X /* Check whether the given vaddr is a valid virtuell address
X * of a shared memory region of this process, i.e. look for it
X * in the process table of pregions.
X */
X PReg_p = u.u_procp->p_region;
X
X while(PReg_p->p_reg != NULL) {
X
X if(PReg_p->p_type == PT_SHMEM &&
X PReg_p->p_regva == (caddr_t)arg)
X break;
X PReg_p++;
X }
X
X if(PReg_p->p_reg == NULL) {
X u.u_error = EINVAL;
X break;
X }
X
X /* Check whether the this is really one of our I/O regions,
X * i.e. region must be known to us.
X */
X
X for(i = 0; i < map_cnt; i++) {
X if(PReg_p->p_reg == mmapreg[i].Reg_p)
X break;
X }
X if(i == map_cnt) {
X u.u_error = EINVAL;
X break;
X }
X
X Reg_p = PReg_p->p_reg;
X reglock(Reg_p);
X detachreg(PReg_p, &u);
X u.u_nshmseg--;
X
X /* If FREEREG is requested and no other user is pointing
X * at the region free it and remove it from the internal
X * list.
X */
X if(FreeReg && (Reg_p->r_refcnt == 0)) {
X reglock(Reg_p);
X Reg_p->r_flags &= ~RG_NOFREE;
X freereg(Reg_p);
X for(i = i; i < map_cnt; i++)
X mmapreg[i] = mmapreg[i+1];
X map_cnt--;
X }
X break;
X
X
X /* Return number of currently memory mapped I/O regions.
X */
X case GETNMMREG:
X u.u_rval1 = map_cnt;
X break;
X
X /* Return information block about currently memory mapped I/O
X * regions.
X */
X case GETMMREG:
X
X for(i = 0; i < map_cnt; i++) {
X ibuf.physaddr = mmapreg[i].physaddr;
X ibuf.length = ctob(mmapreg[i].Reg_p->r_pgsz);
X ibuf.refcnt = mmapreg[i].Reg_p->r_refcnt;
X if(copyout(&ibuf, arg, sizeof(ibuf)) == -1) {
X u.u_error = EFAULT;
X return;
X }
X arg += sizeof(ibuf);
X }
X break;
X
X
X /* Return version number
X */
X case GETVERSION:
X u.u_rval1 = MMAPVERSION;
X break;
X
X
X default:
X u.u_error = EINVAL;
X break;
X
X }
X}
X
X
X/* Find a virtual mapping address.
X */
Xstatic caddr_t FindVirtAddr(size)
X uint size;
X{
X register caddr_t vregaddr;
X register caddr_t vmapaddr = (caddr_t)UVMMAP;
X register preg_t *preg_p = u.u_procp->p_region;
X
X /* Go through the process regions table...
X */
X while(preg_p->p_reg != NULL) {
X
X#ifdef DEBUG
X printf("MMAP: Try vmapaddr %x\n", vmapaddr);
X#endif
X /* If region grows down, use previous MMAPLBA boundary address as
X * starting address. Round up the 0x????3fffc aligned (ending) address
X * before.
X */
X if((preg_p->p_reg)->r_flags & RG_DOWN)
X vregaddr = prev_ba(next_ba(preg_p->p_regva) -
X ctob((preg_p->p_reg)->r_pgsz));
X else
X vregaddr = preg_p->p_regva;
X#ifdef DEBUG
X printf("MMAP: vregaddr = %x\n", vregaddr);
X#endif
X
X /* Search for process region with address above the desired
X * mapping address.
X */
X if(vmapaddr > vregaddr) {
X preg_p++;
X continue;
X }
X
X /* If address is already in use try next address at MMAPLBA boundary
X * after end of this region.
X */
X if(vmapaddr == vregaddr) {
X vmapaddr = next_ba(vregaddr + ctob((preg_p->p_reg)->r_pgsz));
X preg_p++;
X continue;
X }
X
X /* If desired start and end addresses are below this region
X * use this address for mapping, otherwise try next address at
X * MMAPLBA boundary after end of this region.
X */
X if((vmapaddr + size - 1) < vregaddr) {
X#ifdef DEBUG
X printf("MMAP: Take %x\n", vmapaddr);
X#endif
X return vmapaddr;
X }
X vmapaddr = next_ba(vregaddr + ctob((preg_p->p_reg)->r_pgsz));
X preg_p++;
X }
X
X /* If no hole between process regions found, but current vmapaddr
X * (end address) is still below the maximal possible user virtual
X * address, then use it.
X */
X if((vmapaddr + size - 1) < (caddr_t)MAXUVADR)
X return vmapaddr;
X
X /* Found no hole... */
X return NULL;
X}
X
END_OF_FILE
if test 15554 -ne `wc -c <'mmap-2.2.3/mmap.c'`; then
echo shar: \"'mmap-2.2.3/mmap.c'\" unpacked with wrong size!
fi
# end of 'mmap-2.2.3/mmap.c'
fi
if test -f 'mmap-2.2.3/mmap.man' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mmap-2.2.3/mmap.man'\"
else
echo shar: Extracting \"'mmap-2.2.3/mmap.man'\" \(7901 characters\)
sed "s/^X//" >'mmap-2.2.3/mmap.man' <<'END_OF_FILE'
X.\" Copyright (c) 1993 by Thomas Wolfram
X.TH mmap 7L "2.2.3, 22 November 1993" "Version 2.2.3"
X.de BP
X.sp
X.ti -.2i
X\(**
X..
X.SH NAME
Xmmap \- \fBMMAP\fP ioctl commands (memory mapped I/O support)
X.SH SYNOPSIS
X.br
X#include <sys/types.h>
X.br
X#ifndef SCO
X.br
X#include <sys/at_ansi.h>
X.br
X#include <sys/kd.h>
X.br
X#else
X.br
X#include <sys/vtkd.h>
X.br
X#endif
X.br
X#include <sys/sysmacros.h>
X.br
X#include <sys/immu.h>
X.br
X#include <sys/region.h>
X.br
X#include <sys/mmap.h>
X.P
Xint ioctl(fildes, command, arg);
X.br
Xint fildes, command;
X.SH DESCRIPTION
X.I MMAP
Xis a pseudo device driver which provides memory mapped I/O for user processes,
Xi.e. direct mapping of physical memory ranges into the user's virtual address
Xspace for fast access. It is especially useful for accessing the linear frame
Xbuffers of certain graphic hardware from the user level.
X.P
XTo execute the \fIMMAP ioctl\fR commands \fIfildes\fR must be an open file
Xdescriptor [see \fIopen(2)\fR] that refers to the special character device
X\fI/dev/mmap\fR. The effective user ID of the calling process must be
Xsuperuser.
X.br
XThe driver uses shared memory type regions for mapping. So the maximum
Xnumber of regions the driver can attach to a process is limited by
Xthe maximum number of shared memory regions which can be attached to
Xthe process [see \fIshmget(2), shmop(2), shmctl(2)\fR]. This number
Xis a tunable system parameter (\fISHMSEG\fR) [see \fIkconfig(1),
Xidtune(1M)\fR].
X.br
XThe number of regions which the driver is able to map system-wide (i.e. to
Xall running processes) is limited too. This number is also a tunable
Xsystem parameter (\fINMMAPREG\fR).
X.P
XNote, the \fIMMAP\fR driver grows the virtual address space of the calling
Xprocess by itself. Allocating address space before with \fImalloc(3)\fR
Xisn't necessary and will not work.
X.br
XThe mapping regions allocated by the driver will always be sharable, never
Xprivate to a process. Regions can be of type read/write or read/only.
XThis depends from the \fImode\fR \fI/dev/mmap\fR is opened [see \fIopen(2)\fR].
XOnce a region is allocated and mapped to a process it will normally remain
Xin the system (until reboot) even if the last process which pointed at it
Xdetaches it from its address space. (This is not much waste since
Xthe \fIMMAP\fR driver allocates no physical pages for the mapping region.)
XBut with the \fIUNMAPRM\fR ioctl removing after unmapping can be
Xrequested [see below and \fImmaprm(1L)\fR].
XIf a process wants to map in the same memory range like another one (e.g. if
Xit's the same program which is running again) it will be attached with the
Xalready existing region by the driver. Same applies if the processes which
Xrequests the same mapping are running simultaneously.
X.SS Ioctl Calls
XThe following ioctl commands can be used:
X.IP \fBMAP\fP 2
XThis call maps physical memory into the virtual address space of the
Xuser process. The following structure, defined in <sys/kd.h> [see
X\fIdisplay(7)\fR], is pointed to by the argument \fIarg\fR to the ioctl:
X.IP
Xstruct kd_memloc {
X.br
X char *vaddr; /* virtual address to map to */
X.br
X char *physaddr; /* physical address to map from */
X.br
X long length; /* size in bytes to map */
X.br
X long ioflg; /* not used by the \fIMMAP\fR driver */
X.br
X};
X.IP "" 2
XThe \fIvaddr\fR argument is the linear address in the process where the
Xphysical memory range will appear. This address must be on a boundary
Xspecified by the machine dependant constant \fIMMAPLBA\fR, defined in
X<sys/mmap.h>. If \fIvaddr\fR is equal to zero the address is selected by
Xthe driver itself.
X.br
XThe \fIphysaddr\fR argument is the physical address of the memory range
Xthat will be mapped in. It must be on a page boundary.
X.br
XThe \fIlength\fR argument is the size of the memory range that will be
Xmapped in. It will be rounded up to a multiple of the size of a page
Xby the driver.
X.br
XOn success the ioctl will return the virtual address where the memory
Xis mapped in. It will fail if one or more of the following is true:
X.RS 4
X.IP [EPERM] 15
XThe effective user ID of the calling process is not superuser.
X.IP [EFAULT] 15
XThe user address pointed to by \fIarg\fR is illegal.
X.IP [EINVAL] 15
XThe \fIvaddr\fR argument is not equal to zero, and the value is an illegal
Xaddress (not on a MMAPLBA boundary, already used in the process or not
Xbelow \fIMAXUVADR\fR, as defined in <sys/immu.h>).
X.IP [EINVAL] 15
XThe \fIphysaddr\fR argument is not on a page boundary.
X.IP [ENOMEM] 15
XThe \fIvaddr\fR argument is equal to zero and the driver is not able
Xto find a proper region in the user's address space where the memory
Xrange would fit in.
X.IP [ENOMEM] 15
XThe size of the user's virtual address space would exceed the system-imposed
Xlimit.
X.IP [ENOMEM] 15
XNot enough system internal space available to grow the user's virtual
Xaddress space.
X.IP [EMFILE] 15
XThe number of shared memory segments attached to the calling process would
Xexceed the system-imposed limit.
X.IP [EMFILE] 15
XThe number of all memory mapped regions in the system would exceed the
Xdriver-imposed limit.
X.RE 1
X.IP \fBUNMAP\fP 2
XThis call unmaps previously mapped physical memory from the calling process.
XThe argument \fIarg\fR to the ioctl must be the virtual address as
Xreturned by the previous \fIMAP\fR ioctl.
X.br
XIt will fail if one or more of the following is true:
X.RS 4
X.IP [EPERM] 15
XThe effective user ID of the calling process is not superuser.
X.IP [EINVAL] 15
XIf \fIarg\fR is not the start address of a region mapped by the driver to
Xthe calling process.
X.RE 1
X.IP \fBUNMAPRM\fP 2
XSame like \fIUNMAP\fR but removes the concerning region from the systems
Xinternal list, if no other process is still using it [see \fImmaprm(1L)\fR].
X.IP \fBGETNMMREG\fP 2
XThis call returns the number of the memory mapped I/O regions which
Xexists currently in the system [\fIsee mmapstat(1L)\fR]. It requires no
Xargument. It will fail if one or more of the following is true:
X.RS 4
X.IP [EPERM] 15
XThe effective user ID of the calling process is not superuser.
X.RE 1
X.IP \fBGETMMREG\fP 2
XThis call returns the current status of the \fIMMAP\fR driver. The
Xargument \fIarg\fR must be a pointer to an array of elements of
Xthe following type (defined in <sys/mmap.h>):
X.IP
Xtypedef struct mmapinfo {
X.br
X paddr_t physaddr; /* physical address */
X.br
X long length; /* size in bytes */
X.br
X short refcnt; /* number of users */
X.br
X /* pointing currently at this region */
X.br
X} mmapinfo_t;
X.IP "" 2
Xwhich is filled by the driver for every region currently exists.
XThe array must have as much elements as the number returned by the
X\fIGETNMMREG\fR ioctl states [see \fImmapstat(1L)\fR].
XThe command will fail if one or more of the following is true:
X.RS 4
X.IP [EPERM] 15
XThe effective user ID of the calling process is not superuser.
X.IP [EFAULT] 15
XThe user address pointed to by \fIarg\fR is illegal.
X.IP "" 2
X.RE 1
X.IP \fBGETVERSION\fP 2
XReturns version number of driver, e.g. version 2.2.1 would be returned
Xas 0x0221.
X.SH FILES
X.IP \fI/dev/mmap\fR 2
XCharacter device interface to the driver.
X.SH "SEE ALSO"
Xopen(2), ioctl(2), display(7), shmget(2), shmop(2), shmctl(2), kconfig(1),
Xidtune(1M), intro(2), mmapstat(1L), mmaprm(1L).
X.SH DIAGNOSTICS
XUpon sucessful completion, the return value is as follows:
X.RS 5
X.P
XThe \fIMAP\fR ioctl returns the user's address where the physical memory
Xis mapped in.
X.P
XThe \fIUNMAP\fR and \fIUNMAPRM\fR ioctl's return a value of 0.
X.P
XThe \fIGETNMMREG\fR ioctl returns the number of memory mapped I/O regions
Xwhich exists currently in the system.
X.P
XThe \fIGETMMREG\fR ioctl returns a value of 0.
X.P
XThe \fIGETVERSION\fR ioctl returns the version number.
X.RE 1
X.P
XOtherwise, a value of -1 is returned, and \fIerrno\fR [see \fIintro(2)\fR]
Xis set to indicate the error.
X.SH BUGS
XPlease report bugs to:
X.B wolf@prz.tu-berlin.de
Xor
X.BR thomas@aeon.in-berlin.de .
X.SH COPYING
XCopyright (c) 1993 Thomas Wolfram
X.SH AUTHOR
XThomas Wolfram
END_OF_FILE
if test 7901 -ne `wc -c <'mmap-2.2.3/mmap.man'`; then
echo shar: \"'mmap-2.2.3/mmap.man'\" unpacked with wrong size!
fi
# end of 'mmap-2.2.3/mmap.man'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
echo "Sources of the mmap driver v2.2.3 unpacked."
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0