new device pager from mike hibler, hibler@lamp. this is in its 'virgin' state
This commit is contained in:
parent
fa3ccaa273
commit
64c1e3b2f5
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 1990 University of Utah.
|
||||
* Copyright (c) 1991 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* the Systems Programming Group of the University of Utah Computer
|
||||
@ -35,25 +35,27 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)device_pager.c 7.2 (Berkeley) 4/20/91
|
||||
* $Id: device_pager.c,v 1.5 1993/10/02 00:00:21 cgd Exp $
|
||||
* from: @(#)device_pager.c 8.1 (Berkeley) 6/11/93
|
||||
* $Id: device_pager.c,v 1.6 1993/11/03 14:48:42 cgd Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Page to/from special files.
|
||||
*/
|
||||
|
||||
#include "param.h"
|
||||
#include "conf.h"
|
||||
#include "mman.h"
|
||||
#include "malloc.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include "vm.h"
|
||||
#include "vm_page.h"
|
||||
#include "vm_kern.h"
|
||||
#include "device_pager.h"
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/device_pager.h>
|
||||
|
||||
queue_head_t dev_pager_list; /* list of managed devices */
|
||||
queue_head_t dev_pager_list; /* list of managed devices */
|
||||
queue_head_t dev_pager_fakelist; /* list of available vm_page_t's */
|
||||
|
||||
#ifdef DEBUG
|
||||
int dpagerdebug = 0;
|
||||
@ -63,7 +65,28 @@ int dpagerdebug = 0;
|
||||
#define DDB_FAIL 0x08
|
||||
#endif
|
||||
|
||||
void
|
||||
static vm_pager_t dev_pager_alloc
|
||||
__P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
|
||||
static void dev_pager_dealloc __P((vm_pager_t));
|
||||
static int dev_pager_getpage
|
||||
__P((vm_pager_t, vm_page_t, boolean_t));
|
||||
static boolean_t dev_pager_haspage __P((vm_pager_t, vm_offset_t));
|
||||
static void dev_pager_init __P((void));
|
||||
static int dev_pager_putpage
|
||||
__P((vm_pager_t, vm_page_t, boolean_t));
|
||||
static vm_page_t dev_pager_getfake __P((vm_offset_t));
|
||||
static void dev_pager_putfake __P((vm_page_t));
|
||||
|
||||
struct pagerops devicepagerops = {
|
||||
dev_pager_init,
|
||||
dev_pager_alloc,
|
||||
dev_pager_dealloc,
|
||||
dev_pager_getpage,
|
||||
dev_pager_putpage,
|
||||
dev_pager_haspage
|
||||
};
|
||||
|
||||
static void
|
||||
dev_pager_init()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -71,59 +94,67 @@ dev_pager_init()
|
||||
printf("dev_pager_init()\n");
|
||||
#endif
|
||||
queue_init(&dev_pager_list);
|
||||
queue_init(&dev_pager_fakelist);
|
||||
}
|
||||
|
||||
vm_pager_t
|
||||
dev_pager_alloc(handle, size, prot, start_off)
|
||||
static vm_pager_t
|
||||
dev_pager_alloc(handle, size, prot, foff)
|
||||
caddr_t handle;
|
||||
vm_size_t size;
|
||||
vm_prot_t prot;
|
||||
int start_off;
|
||||
vm_offset_t foff;
|
||||
{
|
||||
dev_t dev;
|
||||
vm_pager_t pager;
|
||||
int (*mapfunc)(), nprot;
|
||||
register vm_object_t object;
|
||||
register vm_page_t page;
|
||||
register dev_pager_t devp;
|
||||
register int npages, off;
|
||||
extern int nullop(), enodev();
|
||||
|
||||
int (*mapfunc)();
|
||||
vm_object_t object;
|
||||
dev_pager_t devp;
|
||||
int npages, off;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_FOLLOW)
|
||||
printf("dev_pager_alloc(%x, %x, %x)\n", handle, size, prot);
|
||||
printf("dev_pager_alloc(%x, %x, %x, %x)\n",
|
||||
handle, size, prot, foff);
|
||||
#endif
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* Pageout to device, should never happen.
|
||||
*/
|
||||
if (handle == NULL)
|
||||
panic("dev_pager_alloc called");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Look it up, creating as necessary
|
||||
* Make sure this device can be mapped.
|
||||
*/
|
||||
dev = (dev_t)handle;
|
||||
mapfunc = cdevsw[major(dev)].d_mmap;
|
||||
if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop)
|
||||
return(NULL);
|
||||
|
||||
/*
|
||||
* Offset should be page aligned.
|
||||
*/
|
||||
if (foff & PAGE_MASK)
|
||||
return(NULL);
|
||||
|
||||
/*
|
||||
* Check that the specified range of the device allows the
|
||||
* desired protection.
|
||||
*
|
||||
* XXX assumes VM_PROT_* == PROT_*
|
||||
*/
|
||||
npages = atop(round_page(size));
|
||||
for (off = foff; npages--; off += PAGE_SIZE)
|
||||
if ((*mapfunc)(dev, off, (int)prot) == -1)
|
||||
return(NULL);
|
||||
|
||||
/*
|
||||
* Look up pager, creating as necessary.
|
||||
*/
|
||||
top:
|
||||
pager = vm_pager_lookup(&dev_pager_list, handle);
|
||||
if (pager == NULL) {
|
||||
/*
|
||||
* Validation. Make sure this device can be mapped
|
||||
* and that range to map is acceptible to device.
|
||||
*/
|
||||
dev = (dev_t)handle;
|
||||
mapfunc = cdevsw[major(dev)].d_mmap;
|
||||
if (!mapfunc || mapfunc == enodev || mapfunc == nullop)
|
||||
return(NULL);
|
||||
nprot = 0;
|
||||
if (prot & VM_PROT_READ)
|
||||
nprot |= PROT_READ;
|
||||
if (prot & VM_PROT_WRITE)
|
||||
nprot |= PROT_WRITE;
|
||||
if (prot & VM_PROT_EXECUTE)
|
||||
nprot |= PROT_EXEC;
|
||||
npages = atop(round_page(size));
|
||||
for (off = start_off; npages--; off += PAGE_SIZE)
|
||||
if ((*mapfunc)(dev, off, nprot) == -1)
|
||||
return(NULL);
|
||||
/*
|
||||
* Allocate and initialize pager structs
|
||||
*/
|
||||
@ -135,102 +166,138 @@ dev_pager_alloc(handle, size, prot, start_off)
|
||||
free((caddr_t)pager, M_VMPAGER);
|
||||
return(NULL);
|
||||
}
|
||||
devp->devp_dev = dev;
|
||||
devp->devp_npages = atop(round_page(size));
|
||||
pager->pg_handle = handle;
|
||||
pager->pg_ops = &devicepagerops;
|
||||
pager->pg_type = PG_DEVICE;
|
||||
pager->pg_data = (caddr_t)devp;
|
||||
pager->pg_data = devp;
|
||||
queue_init(&devp->devp_pglist);
|
||||
/*
|
||||
* Allocate object and vm_page structures to describe memory
|
||||
* Allocate object and associate it with the pager.
|
||||
*/
|
||||
npages = devp->devp_npages;
|
||||
object = devp->devp_object = vm_object_allocate(ptoa(npages));
|
||||
object = devp->devp_object = vm_object_allocate(0);
|
||||
vm_object_enter(object, pager);
|
||||
vm_object_setpager(object, pager, (vm_offset_t)start_off,
|
||||
FALSE);
|
||||
devp->devp_pages = (vm_page_t)
|
||||
kmem_alloc(kernel_map, npages*sizeof(struct vm_page));
|
||||
off = start_off;
|
||||
for (page = devp->devp_pages;
|
||||
page < &devp->devp_pages[npages]; page++) {
|
||||
vm_object_lock(object);
|
||||
vm_page_init(page, object, off);
|
||||
page->phys_addr =
|
||||
pmap_phys_address((*mapfunc)(dev, off, nprot));
|
||||
page->wire_count = 1;
|
||||
page->fictitious = TRUE;
|
||||
PAGE_WAKEUP(page);
|
||||
vm_object_unlock(object);
|
||||
off += PAGE_SIZE;
|
||||
}
|
||||
vm_object_setpager(object, pager, (vm_offset_t)0, FALSE);
|
||||
/*
|
||||
* Finally, put it on the managed list so other can find it.
|
||||
* First we re-lookup in case someone else beat us to this
|
||||
* point (due to blocking in the various mallocs). If so,
|
||||
* we free everything and start over.
|
||||
*/
|
||||
if (vm_pager_lookup(&dev_pager_list, handle)) {
|
||||
free((caddr_t)devp, M_VMPGDATA);
|
||||
free((caddr_t)pager, M_VMPAGER);
|
||||
goto top;
|
||||
}
|
||||
queue_enter(&dev_pager_list, pager, vm_pager_t, pg_list);
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_ALLOC)
|
||||
printf("dev_pager_alloc: pages %d@%x\n",
|
||||
devp->devp_npages, devp->devp_pages);
|
||||
if (dpagerdebug & DDB_ALLOC) {
|
||||
printf("dev_pager_alloc: pager %x devp %x object %x\n",
|
||||
pager, devp, object);
|
||||
vm_object_print(object, FALSE);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* vm_object_lookup() gains a reference and also
|
||||
* removes the object from the cache.
|
||||
*/
|
||||
object = vm_object_lookup(pager);
|
||||
#ifdef DIAGNOSTIC
|
||||
devp = (dev_pager_t)pager->pg_data;
|
||||
if (vm_object_lookup(pager) != devp->devp_object)
|
||||
if (object != devp->devp_object)
|
||||
panic("dev_pager_setup: bad object");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_ALLOC) {
|
||||
printf("dev_pager_alloc: pager %x devp %x object %x\n",
|
||||
pager, devp, object);
|
||||
vm_object_print(object, FALSE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return(pager);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
dev_pager_dealloc(pager)
|
||||
vm_pager_t pager;
|
||||
{
|
||||
dev_pager_t devp = (dev_pager_t)pager->pg_data;
|
||||
register vm_object_t object;
|
||||
dev_pager_t devp;
|
||||
vm_object_t object;
|
||||
vm_page_t m;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_FOLLOW)
|
||||
printf("dev_pager_dealloc(%x)\n", pager);
|
||||
#endif
|
||||
queue_remove(&dev_pager_list, pager, vm_pager_t, pg_list);
|
||||
/*
|
||||
* Get the object.
|
||||
* Note: cannot use vm_object_lookup since object has already
|
||||
* been removed from the hash chain.
|
||||
*/
|
||||
devp = (dev_pager_t)pager->pg_data;
|
||||
object = devp->devp_object;
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_ALLOC)
|
||||
printf("dev_pager_dealloc: devp %x object %x pages %d@%x\n",
|
||||
devp, object, devp->devp_npages, devp->devp_pages);
|
||||
printf("dev_pager_dealloc: devp %x object %x\n", devp, object);
|
||||
#endif
|
||||
while (!queue_empty(&object->memq))
|
||||
vm_page_remove((vm_page_t)queue_first(&object->memq));
|
||||
kmem_free(kernel_map, devp->devp_pages,
|
||||
devp->devp_npages * sizeof(struct vm_page));
|
||||
/*
|
||||
* Free up our fake pages.
|
||||
*/
|
||||
while (!queue_empty(&devp->devp_pglist)) {
|
||||
queue_remove_first(&devp->devp_pglist, m, vm_page_t, pageq);
|
||||
dev_pager_putfake(m);
|
||||
}
|
||||
free((caddr_t)devp, M_VMPGDATA);
|
||||
free((caddr_t)pager, M_VMPAGER);
|
||||
}
|
||||
|
||||
static int
|
||||
dev_pager_getpage(pager, m, sync)
|
||||
vm_pager_t pager;
|
||||
vm_page_t m;
|
||||
boolean_t sync;
|
||||
{
|
||||
register vm_object_t object;
|
||||
vm_offset_t offset, paddr;
|
||||
vm_page_t page;
|
||||
dev_t dev;
|
||||
int (*mapfunc)(), prot;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (dpagerdebug & DDB_FOLLOW)
|
||||
printf("dev_pager_getpage(%x, %x)\n", pager, m);
|
||||
#endif
|
||||
return(VM_PAGER_BAD);
|
||||
|
||||
object = m->object;
|
||||
dev = (dev_t)pager->pg_handle;
|
||||
offset = m->offset + object->paging_offset;
|
||||
prot = PROT_READ; /* XXX should pass in? */
|
||||
mapfunc = cdevsw[major(dev)].d_mmap;
|
||||
#ifdef DIAGNOSTIC
|
||||
if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop)
|
||||
panic("dev_pager_getpage: no map function");
|
||||
#endif
|
||||
paddr = pmap_phys_address((*mapfunc)(dev, (int)offset, prot));
|
||||
#ifdef DIAGNOSTIC
|
||||
if (paddr == -1)
|
||||
panic("dev_pager_getpage: map function returns error");
|
||||
#endif
|
||||
/*
|
||||
* Replace the passed in page with our own fake page and free
|
||||
* up the original.
|
||||
*/
|
||||
page = dev_pager_getfake(paddr);
|
||||
queue_enter(&((dev_pager_t)pager->pg_data)->devp_pglist,
|
||||
page, vm_page_t, pageq);
|
||||
vm_object_lock(object);
|
||||
vm_page_lock_queues();
|
||||
vm_page_free(m);
|
||||
vm_page_unlock_queues();
|
||||
vm_page_insert(page, object, offset);
|
||||
PAGE_WAKEUP(m);
|
||||
if (offset + PAGE_SIZE > object->size)
|
||||
object->size = offset + PAGE_SIZE; /* XXX anal */
|
||||
vm_object_unlock(object);
|
||||
|
||||
return(VM_PAGER_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
dev_pager_putpage(pager, m, sync)
|
||||
vm_pager_t pager;
|
||||
vm_page_t m;
|
||||
@ -245,7 +312,7 @@ dev_pager_putpage(pager, m, sync)
|
||||
panic("dev_pager_putpage called");
|
||||
}
|
||||
|
||||
boolean_t
|
||||
static boolean_t
|
||||
dev_pager_haspage(pager, offset)
|
||||
vm_pager_t pager;
|
||||
vm_offset_t offset;
|
||||
@ -256,3 +323,35 @@ dev_pager_haspage(pager, offset)
|
||||
#endif
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
static vm_page_t
|
||||
dev_pager_getfake(paddr)
|
||||
vm_offset_t paddr;
|
||||
{
|
||||
vm_page_t m;
|
||||
int i;
|
||||
|
||||
if (queue_empty(&dev_pager_fakelist)) {
|
||||
m = (vm_page_t)malloc(PAGE_SIZE, M_VMPGDATA, M_WAITOK);
|
||||
for (i = PAGE_SIZE / sizeof(*m); i > 0; i--) {
|
||||
queue_enter(&dev_pager_fakelist, m, vm_page_t, pageq);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
queue_remove_first(&dev_pager_fakelist, m, vm_page_t, pageq);
|
||||
m->flags = PG_BUSY | PG_CLEAN | PG_FAKE | PG_FICTITIOUS;
|
||||
m->phys_addr = paddr;
|
||||
m->wire_count = 1;
|
||||
return(m);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_pager_putfake(m)
|
||||
vm_page_t m;
|
||||
{
|
||||
#ifdef DIAGNOSTIC
|
||||
if (!(m->flags & PG_FICTITIOUS))
|
||||
panic("dev_pager_putfake: bad page");
|
||||
#endif
|
||||
queue_enter(&dev_pager_fakelist, m, vm_page_t, pageq);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 1990 University of Utah.
|
||||
* Copyright (c) 1991 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* the Systems Programming Group of the University of Utah Computer
|
||||
@ -35,45 +35,20 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)device_pager.h 7.1 (Berkeley) 12/5/90
|
||||
* $Id: device_pager.h,v 1.3 1993/05/20 03:59:09 cgd Exp $
|
||||
* from: @(#)device_pager.h 8.1 (Berkeley) 6/11/93
|
||||
* $Id: device_pager.h,v 1.4 1993/11/03 14:48:44 cgd Exp $
|
||||
*/
|
||||
|
||||
#ifndef _VM_DEVICE_PAGER_H_
|
||||
#define _VM_DEVICE_PAGER_H_
|
||||
#ifndef _DEVICE_PAGER_
|
||||
#define _DEVICE_PAGER_ 1
|
||||
|
||||
/*
|
||||
* Device pager private data.
|
||||
*/
|
||||
struct devpager {
|
||||
queue_head_t devp_list; /* list of managed devices */
|
||||
dev_t devp_dev; /* devno of device */
|
||||
vm_page_t devp_pages; /* page structs for device */
|
||||
int devp_npages; /* size of device in pages */
|
||||
int devp_count; /* reference count */
|
||||
queue_head_t devp_pglist; /* list of pages allocated */
|
||||
vm_object_t devp_object; /* object representing this device */
|
||||
};
|
||||
typedef struct devpager *dev_pager_t;
|
||||
|
||||
#define DEV_PAGER_NULL ((dev_pager_t)0)
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
void dev_pager_init();
|
||||
vm_pager_t dev_pager_alloc();
|
||||
void dev_pager_dealloc();
|
||||
boolean_t dev_pager_getpage(), dev_pager_putpage();
|
||||
boolean_t dev_pager_haspage();
|
||||
|
||||
struct pagerops devicepagerops = {
|
||||
dev_pager_init,
|
||||
dev_pager_alloc,
|
||||
dev_pager_dealloc,
|
||||
dev_pager_getpage,
|
||||
dev_pager_putpage,
|
||||
dev_pager_haspage
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !_VM_DEVICE_PAGER_H_ */
|
||||
#endif /* _DEVICE_PAGER_ */
|
||||
|
Loading…
Reference in New Issue
Block a user