Subject: aperture driver for XFree86
To: None <current-users@sun-lamp.cs.berkeley.edu>
From: Matthieu Herrb <matthieu@laas.fr>
List: current-users
Date: 06/20/1994 21:10:30
Hi,

Since the new kernel code that prevents /dev/mem from being openend
read/write breaks some functionality of XFree86 with card that take
advantage of direct linear mapping of the video memory, I wrote a
little loadable kernel module to get around this protection. 

It mimics the functionality of the Solaris x86 aperture driver.

The code is appenend below, including a patch to use it with XFree86
2.1.1. I hope to make some pre-compiled servers available soon.

Please note that this code is to be considered as beta: I need tests
and feedback on it before its inclusion in the future XFree86 3.1
release. 

Also I'd like to hear about the principle of such a module from the
core team. Since it partially defeats the kernel security are there
other ways to get the frambuffers mapped in memory ? Are there
additional precautions to take in the driver ?

Thank you in advance.

					Matthieu

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	DISCLAIMER
#	Makefile
#	README
#	aperture.c
#	apinstall
#	aptest.c
#	lkm.c
#	version.c
#	version.h
#	xf86-2.1.1.patch
#
echo x - DISCLAIMER
sed 's/^X//' >DISCLAIMER << 'END-of-DISCLAIMER'
XCopyright 1994 Matthieu Herrb (matthieu@laas.fr)
X
XPermission to use, copy, modify, distribute, and sell this software
Xand its documentation for any purpose is hereby granted without fee,
Xprovided that the above copyright notice appear in all copies and that
Xboth that copyright notice and this permission notice appear in
Xsupporting documentation, and that the name of Matthieu Herrb be used
Xin advertising or publicity pertaining to distribution of the software
XMatthieu Herrb make no representations about the suitability of this
Xsoftware for any purpose.  It is provided "as is" without express or
Ximplied warranty.
X
XDISCLAIMER: MATTHIEU HERRB DISCLAIMS ALL WARRIENTS WITH REGARD TO THIS
XSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, AND
XFITNESS, IN NO EVENT SHALL DOUG ANSON, OR DAVID HOLLAND BE LIABLE FOR
XANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
XWHATSOEVER RESULTING FROM USAGE OF THIS SOFTWARE. 
X
END-of-DISCLAIMER
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#
X# Loadable Kernel Module for Sound Blaster Mixer Chip
X#
X# Copyright (c) 1994 Matthieu Herrb
X#
X
XCFLAGS = -g -DKERNEL  -I/sys -I/sys/arch
X
XMODULE = ap
XPOSTINSTALL = apinstall
X
XSRCS = aperture.c lkm.c version.c
XOBJS = $(SRCS:.c=.o)
X
Xall: $(MODULE).o aptest
X
X$(MODULE).o: $(OBJS)
X	$(LD) -r -o $(MODULE).o $(OBJS)
X
Xaptest:	aptest.c
X	$(CC) -g -o aptest aptest.c
X
Xclean:
X	rm -f $(MODULE).o $(OBJS) aptest
X
Xload:
X	modload -v -o$(MODULE) -e$(MODULE) -p$(POSTINSTALL) $(MODULE).o
X
Xunload:
X	modunload -n $(MODULE)
X
X.c.o:
X	$(CC) -c $(CPPFLAGS) $(CFLAGS) $<
X
X.include <bsd.dep.mk>
END-of-Makefile
echo x - README
sed 's/^X//' >README << 'END-of-README'
XXFree86 Framebuffer aperture driver for NetBSD.
X
X(Note, see the DISCLAIMER file before using this driver!)
X
XThis module was written to help work around the security feature of
XNetBSD 0.9C that prevents read/write access to /dev/mem. 
X
XSince XFree86 can take advantage of having direct access to video
Xmemory (especially with VLB and PCI cards).
X
XThis driver works like the standard /dev/mem driver. It just doesn't
Xcheck  the kernel 'securitylevel' variable before allowing the
Xopen. The driver only implements the open(), close() and mmap()
Xcalls. 
X
XThis work is heavily inspired from the Solaris x86 aperture driver by 
XDoug Anson (danson@lgc.com) and David Holland (davidh@use.com).
X
XInstallation:
X-------------
X
X1. run make depend && make
X
X2. As root run 'make load' to load the module into kernel
X   copy ap.o somewhere in your tree (I use /usr/kernel/modules to
X   mimic Solaris)
X
X3. add the line  somehere at the end of /etc/rc.local
X	modload -v -o ap -e ap /usr/kernel/modules/ap.o
X   to reload it after every reboot.
X
X4. since NetBSD modload does not execute post-install scripts, create
X   the device manually:
X  
X   WARNING: be sure to understand what you'll do before proceeding
X
X   a) find out what major device number will be allocated to you by
X      modload. Modload allocates major numbers beginning at 29. So if
X      'ap' is your only device driver module, it will have major
X      number 29. If it's the third, it will be 31...
X
X   b) goto the /dev directory and type ``mknod xf86 c 29 0'' (replace
X      29 by the appropriate value if you load more than one device
X      friver module.
X
X      Make sure that rc.local loads the module at the same position
X      that you did now.
X
X   c) I hope that LKM support will be enhanced soon so this major
X      number allocation stuff can be automated.
X
X5. Test it by running 'aptest' as root. The outpout will look like:
X   (with an AMI BIOS):
X
X# ./aptest
XNOTICE: BIOS mapped [0xf0000 ,size=4096) to addr=0x10073000...
X0123AAAAMMMMIIIIBBBBIIIIOOOOSSSS((((CCCC))))AAAAMMMMIIII11111111////11111111////
XDONE displaying memory contents (80 bytes)
XUNMAPPING [0xf0000 ,size=4096) to addr=0x10073000... and closing...DONE.
XExiting successful...
X
X6. Apply the xf86-2.1.1.patch, rebuild and install the server.
X
XBug reports, comments, suggestions can be sent to matthieu@laas.fr
X
X--Matthieu Herrb
X
END-of-README
echo x - aperture.c
sed 's/^X//' >aperture.c << 'END-of-aperture.c'
X/*
X * Copyright 1994 Matthieu Herrb (matthieu@laas.fr)
X *
X * Permission to use, copy, modify, distribute, and sell this software
X * and its documentation for any purpose is hereby granted without
X * fee, provided that the above copyright notice appear in all copies
X * and that both that copyright notice and this permission notice
X * appear in supporting documentation, and that the name of Matthieu
X * Herrb be used in advertising or publicity pertaining to
X * distribution of the software Matthieu Herrb make no 
X * representations about the suitability of this software for any
X * purpose.  It is provided "as is" without express or implied
X * warranty.
X *
X * DISCLAIMER: MATTHIEU HERRB DISCLAIMS ALL WARRIENTS WITH REGARD TO
X * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY,
X * AND FITNESS, IN NO EVENT SHALL DOUG ANSON, OR DAVID HOLLAND BE
X * LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY
X * DAMAGES WHATSOEVER RESULTING FROM USAGE OF THIS SOFTWARE.
X */
X
X/* 
X * linear framebuffer aperture driver for NetBSD
X */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/errno.h>
X#include <sys/proc.h>
X
X/*
X * Open the device
X */
Xint
Xapopen(dev_t dev, int oflags, int devtype, struct proc *p)
X{
X    struct pcred *pc = p->p_cred;
X
X    if (suser(p->p_ucred, &p->p_acflag) != 0) {
X	return(EPERM);
X    }
X    return(0);
X}
X
X/*
X * Close the device
X */
Xint
Xapclose(dev_t dev, int cflags, int devtype, struct proc *p)
X{
X
X    return(0);
X}
X
X/*
X *  mmap() physical memory sections
X */
Xint
Xapmmap(dev_t dev, int offset)
X{
X
X    if  (minor(dev) == 0) {
X	return i386_btop(offset);
X    } else {
X	return(-1);
X    }
X}
X       
END-of-aperture.c
echo x - apinstall
sed 's/^X//' >apinstall << 'END-of-apinstall'
X#! /bin/sh
Xecho "Module Id: $1"
Xecho "Module type: $2"
Xecho "Device numbers: $3 $4"
X
X# cd /dev
X# mknod xf86 c $3 0
END-of-apinstall
echo x - aptest.c
sed 's/^X//' >aptest.c << 'END-of-aptest.c'
X/* 
X * Copyright 1994  	Doug Anson, danson@lgc.com & David Holland, davidh@use.com
X *
X * Author: Doug Anson (danson@lgc.com)
X * Date  : 2/21/94
X * Modifed: David Holland (davidh@use.com)
X * Log:
X * 		DWH - Changed names/added comments	2/23/94
X * 		DWH - Removed annoying delays.		2/23/94
X * 
X * This program test the fb aperture driver by 'cheating'
X * it uses the aperture driver to access/read the main
X * system BIOS header
X * 
X * Copyright notice:
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 Doug Anson, and David Holland be used in
X * advertising or publicity pertaining to distribution of the software 
X * Doug Anson, and David Holland make no * representations about the 
X * suitability of this software for any purpose.
X * It is provided "as is" without express or implied warranty.
X *
X * Disclaimer:
X * DOUG ANSON, AND DAVID HOLLAND DISCLAIMS ALL WARRIENTS WITH REGARD TO THIS 
X * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS, 
X * IN NO EVENT SHALL DOUG ANSON, OR DAVID HOLLAND BE LIABLE FOR ANY SPECIAL, 
X * INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM 
X * USAGE OF THIS SOFTWARE.
X */
X
X/*
X * linear framebuffer aperture driver test program
X */
X
X/* 
X * $Id
X */
X
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/mman.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <errno.h>
X
X#if !defined(sun)
Xextern void exit(int);
Xextern caddr_t mmap();
Xextern int close();
Xextern int munmap();
X#endif
X
X/* framebuffer access defines */
X#define AP_DEV		"/dev/xf86"	/* framebuffer apperture device		*/
X#define PADDR		0xf0000				/* offset from fbmem base     		*/
X#define BUF_LENGTH  0x1000				/* length in bytes -- ignored 		*/
X
X/* debug testing defines */
X#define START_INDEX	0		/* display starting index(>=0)*/
X#define STOP_INDEX	80		/* display stopping index	  */
X#define INCR		1		/* display increment		  */
X
X/* main program */
Xint main(int argc,char **argv)
X{
X	caddr_t	addr = (caddr_t)0;
X	int		fb_dev;
X	long	start = START_INDEX;
X	long	stop = STOP_INDEX;
X	int		i;
X
X	/* open the framebuffer device */
X	fb_dev = open (AP_DEV,O_RDWR);
X	if (fb_dev < 0)
X	{
X		/* failed to open framebuffer driver */
X		printf("ERROR: failed to open %s\n",AP_DEV);
X		perror("ERROR: open()");
X		exit(1);
X	} 
X
X	/* memory map the framebuffer */
X	addr = (caddr_t)mmap((caddr_t)0,BUF_LENGTH,PROT_READ|PROT_WRITE,MAP_SHARED,
X			             fb_dev,(off_t)PADDR);
X	if (addr == (caddr_t)-1)
X	{
X		/* failed to memory map framebuffer driver */
X		printf("ERROR: failed to mmap [0x%x ,size=%d bytes)\n",
X			   PADDR,BUF_LENGTH);
X		perror("ERROR: mmap()");
X		close(fb_dev);
X		exit(1);
X	}
X	else
X	{
X		/* frame buffer mapped */
X		close(fb_dev);
X		printf("NOTICE: BIOS mapped [0x%x ,size=%d) to addr=0x%x...\n",
X			   PADDR,BUF_LENGTH,(int)addr);
X
X		/* display the buffer */
X    	for(i=start;i<stop;i=i+INCR)
X			printf("%c",addr[i]);
X        	/* printf("addr[%d]=%c\n",i,addr[i]);
X			 */
X		printf("\nDONE displaying memory contents (%d bytes)\n",stop);
X
X		/* unmap and close */
X		printf("UNMAPPING [0x%x ,size=%d) to addr=0x%x... and closing...",
X               PADDR,BUF_LENGTH,(int)addr);
X		munmap(addr,BUF_LENGTH);
X		printf("DONE.\n");
X		printf("Exiting successful...\n");
X		exit(0);
X	}
X	return 1;
X}
END-of-aptest.c
echo x - lkm.c
sed 's/^X//' >lkm.c << 'END-of-lkm.c'
X/*
X * Copyright 1994 Matthieu Herrb (matthieu@laas.fr)
X *
X * Permission to use, copy, modify, distribute, and sell this software
X * and its documentation for any purpose is hereby granted without
X * fee, provided that the above copyright notice appear in all copies
X * and that both that copyright notice and this permission notice
X * appear in supporting documentation, and that the name of Matthieu
X * Herrb be used in advertising or publicity pertaining to
X * distribution of the software Matthieu Herrb make no 
X * representations about the suitability of this software for any
X * purpose.  It is provided "as is" without express or implied
X * warranty.
X *
X * DISCLAIMER: MATTHIEU HERRB DISCLAIMS ALL WARRIENTS WITH REGARD TO
X * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY,
X * AND FITNESS, IN NO EVENT SHALL DOUG ANSON, OR DAVID HOLLAND BE
X * LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES, OR ANY
X * DAMAGES WHATSOEVER RESULTING FROM USAGE OF THIS SOFTWARE.
X */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/conf.h>
X#include <sys/uio.h>
X#include <sys/exec.h>
X#include <sys/lkm.h>
X#include <errno.h>
X#include "version.h"
X
X/* cdevsw-specific types */
X#define dev_type_read(n)        int n __P((dev_t, struct uio *, int))
X#define dev_type_write(n)       int n __P((dev_t, struct uio *, int))
X#define dev_type_ioctl(n) \
X        int n __P((dev_t, int, caddr_t, int, struct proc *))
X#define dev_type_stop(n)        int n __P((struct tty *, int))
X#define dev_type_reset(n)       int n __P((int))
X#define dev_type_select(n)      int n __P((dev_t, int, struct proc *))
X#define dev_type_mmap(n)        int n __P(())
X
Xextern int apopen(dev_t dev, int oflags, int devtype, struct proc *p);
Xextern int apclose(dev_t dev, int fflags, int devtype, struct proc *p);
Xextern int apmmap(dev_t dev, int offset);
X
Xstatic struct cdevsw newdev = {
X    apopen, apclose, 
X    (dev_type_read((*))) enodev, (dev_type_write((*))) enodev,
X    (dev_type_ioctl((*))) enodev, 
X    (dev_type_stop((*))) enodev,
X    (dev_type_reset((*))) nullop, (struct tty **) 0,
X    seltrue, (dev_type_mmap((*))) apmmap, 0};
X
XMOD_DEV("ap", LM_DT_CHAR, -1, &newdev)
X
Xstatic int 
Xap_load(struct lkm_table *lkmtp, int cmd)
X{
X    if (cmd == LKM_E_LOAD) {
X	printf("\n Aperture driver for XFree86 version %s.%s\n",
X	       ap_major_version, ap_minor_version);
X    }
X    return(0);
X}
X
Xint
Xap(struct lkm_table *lkmtp, int cmd, int ver)
X{
X    DISPATCH(lkmtp, cmd, ver, ap_load, nosys, nosys)
X}
X
X
X    
END-of-lkm.c
echo x - version.c
sed 's/^X//' >version.c << 'END-of-version.c'
X/*
X * Loadable Kernel Module for XFree86 Aperture driver
X *
X * Copyright (c) 1994 Matthieu Herrb
X */
Xchar *ap_major_version = "1";
Xchar *ap_minor_version = "0";
END-of-version.c
echo x - version.h
sed 's/^X//' >version.h << 'END-of-version.h'
X/*
X * Loadable Kernel Module for XFree86 Aperture driver
X *
X * Copyright (c) 1994 Matthieu Herrb
X */
Xextern char *ap_major_version;
Xextern char *ap_minor_version;
END-of-version.h
echo x - xf86-2.1.1.patch
sed 's/^X//' >xf86-2.1.1.patch << 'END-of-xf86-2.1.1.patch'
X*** mit/config/x386.cf.ORIG	Mon Jun 20 08:20:07 1994
X***************
X*** 868,873 ****
X--- 868,882 ----
X  # define SOLX86apertureFlags	/**/
X  #endif
X  
X+ #ifndef HasNetBSDApertureDrv
X+ # define HasNetBSDApertureDrv	NO
X+ #endif
X+ #if HasNetBSDApertureDrv
X+ # define NetBSDApertureFlags	-DHAS_SOLX86_APERTUREDRV
X+ #else
X+ # define NetBSDApertureFlags	/**/
X+ #endif
X+ 
X  #define CppCmd                  /usr/ccs/lib/cpp
X  #define PreProcessCmd           /usr/ccs/lib/cpp
X  
X***************
X*** 925,931 ****
X  #endif
X  
X  #define ServerExtraDefines      GccGasOption -DXDMCP MallocFlags LinkKitFlags \
X!                                 -DAVOID_GLYPHBLT SOLX86apertureFlags
X  
X  #if SCOLocalConnSysv4
X  # define Acp                    -DSVR4_ACP
X--- 934,941 ----
X  #endif
X  
X  #define ServerExtraDefines      GccGasOption -DXDMCP MallocFlags LinkKitFlags \
X!                                 -DAVOID_GLYPHBLT SOLX86apertureFlags \
X! 				NetBSDApertureFlags
X  
X  #if SCOLocalConnSysv4
X  # define Acp                    -DSVR4_ACP
X*** mit/config/site.def.ORIG	Mon Jun 20 08:19:52 1994
X***************
X*** 345,350 ****
X--- 345,353 ----
X  /* Uncomment this to include support for Solaris aperture driver */
X  /* #define HasSolx86apertureDrv	YES */
X  
X+ /* Uncomment this to include support for NetBSD aperture driver */
X+ #define HasNetBSDApertureDrv	YES 
X+ 
X  /* Uncomment this if you want to build a debuggable server */
X  /* #define DebuggableServer	YES */
X  
X*** mit/server/ddx/x386/os-support/bsd/bsd_video.c.ORIG1	Mon Jun 20 08:08:42 1994
X***************
X*** 63,68 ****
X--- 63,74 ----
X  static Bool useDevMem = FALSE;
X  static int  devMemFd = -1;
X  
X+ #ifdef HAS_NETBSD_APERTUREDRV
X+ #define DEV_MEM "/dev/xf86"
X+ #else
X+ #define DEV_MEM "/dev/mem"
X+ #endif
X+ 
X  /*
X   * Check if /dev/mem can be mmap'd.  If it can't print a warning when
X   * "warn" is TRUE.
X***************
X*** 74,85 ****
X  	pointer base;
X  
X  	devMemChecked = TRUE;
X! 	if ((fd = open("/dev/mem", O_RDWR)) < 0)
X  	{
X  	    if (warn)
X  	    {
X! 	        ErrorF("checkDevMem: warning: failed to open /dev/mem (%s)\n",
X! 		       strerror(errno));
X  	        ErrorF("\tlinear fb access unavailable\n");
X  	    }
X  	    useDevMem = FALSE;
X--- 80,91 ----
X  	pointer base;
X  
X  	devMemChecked = TRUE;
X! 	if ((fd = open(DEV_MEM, O_RDWR)) < 0)
X  	{
X  	    if (warn)
X  	    {
X! 	        ErrorF("checkDevMem: warning: failed to open %s (%s)\n",
X! 		       DEV_MEM, strerror(errno));
X  	        ErrorF("\tlinear fb access unavailable\n");
X  	    }
X  	    useDevMem = FALSE;
X***************
X*** 122,136 ****
X  	    int memFd;
X  	    if ((memFd = devMemFd) < 0) 
X  	    {
X! 		FatalError("xf86MapVidMem: failed to open /dev/mem (%s)\n",
X! 			   strerror(errno));
X  	    }
X  	    base = (pointer)mmap((caddr_t)0, Size, PROT_READ|PROT_WRITE,
X  				 MAP_FILE, memFd, (off_t)Base);
X  	    if (base == (pointer)-1)
X  	    {
X! 		FatalError("%s: could not mmap /dev/mem [s=%x,a=%x] (%s)\n",
X! 			   "xf86MapVidMem", Size, Base, strerror(errno));
X  	    }
X  	    return(base);
X  	}
X--- 128,143 ----
X  	    int memFd;
X  	    if ((memFd = devMemFd) < 0) 
X  	    {
X! 		FatalError("xf86MapVidMem: failed to open %s (%s)\n",
X! 			   DEV_MEM, strerror(errno));
X  	    }
X  	    base = (pointer)mmap((caddr_t)0, Size, PROT_READ|PROT_WRITE,
X  				 MAP_FILE, memFd, (off_t)Base);
X  	    if (base == (pointer)-1)
X  	    {
X! 		FatalError("%s: could not mmap %s [s=%x,a=%x] (%s)\n",
X! 			   "xf86MapVidMem", DEV_MEM, Size, Base, 
X! 			   strerror(errno));
X  	    }
X  	    return(base);
X  	}
END-of-xf86-2.1.1.patch
exit


------------------------------------------------------------------------------