mmap() under SunOS 4.0 [LONG]

Tom Wheatley wheatley at cme.nist.gov
Fri Sep 22 23:39:30 AEST 1989


Yes, the man pages are somewhat useless for the mmap() call. The manual on
WRITING DEVICE DRIVERS (for people who actually read them) is fortunately
very clear. We tackled this problem back in early June and have had no
problems whatsoever since then. The major changes are below. Each program
is standalone for simple testing purposes. I do not profess to be the most
elegant code writer, just a basic hack. Still, the code works. 

The old 3.5 version was : 

#include <sys/mman.h>  /* used for mmap call */
#include <sys/types.h> /* used for mmap call */
#include <sys/file.h>  /* used for open call */

main()
{
int vme16index;  /* index from 0 in VME16D16 space */
int junk;        /* placeholder */
int readjunk;    /* placeholder */
int memfd;       /* file descriptor of VME16D16 space */
char * v16base;  /* base address from mmap call, the char causes all */
                 /* addresses to be interpreted as bytes.  */
int i, ps, errno;

/*========  Assign physical device to virtual memory address ====*/

  memfd = open ("/dev/vme16d16", O_RDWR);
  if (memfd <0){
     perror("/dev/vme16d16");
     _exit();
               }
  ps= getpagesize();
  v16base = (char*) valloc(ps);
  if (v16base == 0){ perror("valloc"); _exit(); }

  printf("page size is %x\n", ps);

  printf("The Bit-3 is strapped for vme16d16 between 0 and 2000.\n");
  printf("We get ps bytes starting from 0.\n");

  errno = mmap(v16base,ps,PROT_READ|PROT_WRITE,MAP_SHARED,memfd,0x0);
  if (errno)  { perror("mmap"); _exit(); }

/* ========= try to read board=========== =================*/
    for (i = 0; i < 10; i ++)
    {
    printf("Enter desired index between 0 and 2000.\n");
    scanf("%x", &vme16index);
    printf("trying to read location %x\n", vme16index);

    junk  = *(v16base + vme16index);  /* attempt a read */
    printf("junk read is %x\n", junk );

    printf("Enter new data for write attempt.\n");
    scanf("%x", &junk);

    *(v16base + vme16index) = junk;   /* attempt a write */
    readjunk  = *(v16base + vme16index);  /* read it back */
    printf("read it back, junk wrote is %x\n", readjunk );
    }                

    close(memfd);              /* clean-up and return to caller */
}

If you want to use vme24 address space, just replace all vme16's with 
vme24's and v16base with v24base. The major changes under 4.0 were a lot 
of bells and whistles, most of which don't work, are not implemented, or 
just don't make sense in my opinion. The MAP_SHARED is the only flag I was 
able to get working. The MAP_FIXED, although it sounds like what most people 
would like, is discouraged according to the man pages. This is enforced by 
the refusal of the mmap call to work under MAP_FIXED. A working test program 
for version 4.0.3 is as follows: 

#include <stdio.h>
#include <sys/mman.h>  /* used for mmap call */
#include <sys/types.h> /* used for mmap call */
#include <sys/file.h>  /* used for open call */

main()
{
int vmeoff;      /* actual address of VME24D16 space */ 
int vme24index;  /* index from above offset */
int junk[2048];        /* placeholder */
int readjunk[2048];    /* placeholder */
int memfd;       /* file descriptor of VME24D16 space */
int *v24base;   /* base address from mmap call */
int ps;
int i,j;


/*========  Assign physical device to virtual memory address ====*/

  memfd = open ("/dev/vme24d16", O_RDWR);
  if (memfd <0){ perror("/dev/vme24d16");  _exit(); }

  ps= getpagesize();
  printf("page size is %x\n", ps);

/* We start at the offset vmeoff, continuing for ps bytes. Both must be */
/* multiples of the page size.                                            */

   printf("vmeoff must be a multiple of the page size.\n");
   printf("Use vmeoff to get to multiples like B00000.\n");
   printf("Use index of 100 to get to internal locations like B00100.\n");
   printf("Enter vmeoff in HEX. We get ps bytes starting from there.\n");
   scanf("%x", &vmeoff);

   v24base = mmap((caddr_t)0,ps,PROT_READ|PROT_WRITE,MAP_SHARED,memfd,vmeoff);
   printf("v24base is %d\n", v24base );
   printf("v24base is %x\n", v24base ); 

   if (v24base == (caddr_t)-1) { perror("mmap"); _exit(); }

/* ========= try to read board=========== =================*/
    for (i = 0; i < 2047; i ++)
      {
       readjunk[i] = i;
       junk[i] = i;
      }
    printf("Enter desired index from above vmeoff not to exceed ps.\n");
    scanf("%x", &vme24index);
    printf("trying to read location %x\n", vmeoff + vme24index);

    for (j = 0; j < 100000; j ++)
    {
    for (i = 0; i < 2047; i ++)
      {
    *(v24base + vme24index + i) = junk[i];  /* attempt a write*/
      }
    for (i = 0; i < 2047; i ++)
      {
    readjunk[i]  = *(v24base + vme24index + i);  /* attempt a read */
      }    
    }                

    close(memfd);              /* clean-up and return to caller */
}

The major things here are the non-use of the valloc call, and the (very) 
different format of the mmap call and subsequent test for error. This was 
found in the WRITING DEVICE DRIVERS, and was quite clear. I just wish they 
had put in the the man pages. Actually, since the addr under 4.0 is created 
by the mmap call, it is clearer to me than under 3.5, where the addr 
was magically changed invisible to the user. In any case, have fun, and 
write back or call if you have any problems.

Tom Wheatley  (301)-975-3449   



More information about the Comp.sys.sun mailing list