home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-27 | 38.9 KB | 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
-