Subject: problem with bus_space_map
To: None <tech-kern@netbsd.org>
From: Christian Groessler <cpg@aladdin.de>
List: tech-kern
Date: 02/10/2004 22:06:37
Hi,

I'm trying to write a driver (lkm) which maps the last 8MB of the
memory address space on i386.

See below for the lkm code.

It successfully loads, but when I unload it, the bus_space_unmap call
causes the machine to reboot.

Now when I use (MEM_LEN-1) instead of MEM_LEN for bus_space_[un]map,
I get a panic when I unload the lkm (panic: extent_free: region not
found).

It also appears that in the MEM_LEN case, the mapping isn't really
done, since the mapped address when using MEM_LEN-1 appears in a 8MB
chunk in 'pmap 0' output, whereas with MEM_LEN the mapped address
doesn't appear and also looks suspicious (< 0xC0000000).

I'm new to this so probably I'm doing something wrong. Any help is
appreciated!

chris



--------------------------------------
/* $Id: i860ldr-netbsd.c,v 1.4 2004/02/10 20:23:49 chris Exp $
 *
 * NetBSD Hauppauge i860 program loader driver
 * (c) Copyright 2004 by Christian Groessler, chris@groessler.org
 *
 * netbsd current feb-2004
 */

#define VERSION_HIGH  0
#define VERSION_LOW   91
#define VERSION_ASC   "0.91"
#define VERSION_BETA  1	 /* this version is beta */

#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <machine/bus.h>
/*#include "i860ioctl.h"*/


/*
 * function prototypes
 */
static int i860ldr_open(dev_t dev, int flag, int mode, struct proc *p);
static int i860ldr_close(dev_t dev, int flag, int mode, struct proc *p);
static int i860ldr_write(dev_t dev, struct uio *uio, int flags);

/*
 * global data
 */
static unsigned int i860memsize = 8192;  /* in kb */

#define MEM_BASE (0x100000000LL - i860memsize * 1024)
#define MEM_LEN ((unsigned int)(0x100000000LL - MEM_BASE))
static void *mem_base;

dev_type_open(i860ldr_open);
dev_type_close(i860ldr_close);
dev_type_write(i860ldr_write);

static const struct cdevsw i860ldr_cdevsw = {
    i860ldr_open, i860ldr_close, noread, i860ldr_write, noioctl,
    nostop, notty, nopoll, nommap, nokqfilter,
};


MOD_DEV("i860ldr", "i860ldr", NULL, -1, &i860ldr_cdevsw, -1)

static bus_space_handle_t memh;

static int
i860ldr_init(void)
{
    if (bus_space_map(X86_BUS_SPACE_MEM, MEM_BASE, MEM_LEN, BUS_SPACE_MAP_LINEAR, &memh)) {
        printf("i860ldr_init: cannot map phys. memory area %08lX, len %08lX\n",
               (unsigned long)MEM_BASE, (unsigned long)MEM_LEN);
        return ENXIO;
    }
    mem_base = bus_space_vaddr(X86_BUS_SPACE_MEM, memh);
    return 0;
}

static int
i860ldr_shutdown(void)
{
    bus_space_unmap(X86_BUS_SPACE_MEM, memh, MEM_LEN);
    return 0;
}

static int
i860ldr_lkm(struct lkm_table *lkmtp, int cmd)
{
    int error = 0;

    switch (cmd) {
	case LKM_E_LOAD:
            error = i860ldr_init();
            break;
	case LKM_E_UNLOAD:
            error = i860ldr_shutdown();
            break;
	case LKM_E_STAT:
            error = lkmdispatch(lkmtp, cmd);
            break;
    }
    return (error);
}

/*
 * i860ldr_lkmentry
 * External entry point.
 */
int i860ldr_lkmentry (struct lkm_table *lkmtp, int cmd, int ver)
{
    DISPATCH(lkmtp, cmd, ver, i860ldr_lkm, i860ldr_lkm, lkm_nofunc);
}


/*
 * open function
 */
static int i860ldr_open(dev_t dev, int flag, int mode, struct proc *p)
{
    if (minor(dev) != 0) return ENXIO;

    return 0;
}


/*
 * close function
 */
static int i860ldr_close(dev_t dev, int flag, int mode, struct proc *p)
{
    return 0;
}


/*
 * write function
 * access the mapped memory...
 */
static int i860ldr_write(dev_t dev, struct uio *uio, int flags)
{
    unsigned char c;

    printf("i860ldr_write: ouch!\n");
    c = *(unsigned char *)mem_base;
    printf("i860ldr_write: nono, it didn't hurt! (c = %02X)\n", c);
    return 0;
}
--------------------------------------