code:
/*	$OpenBSD: bus_dma.c,v 1.32 2014/12/23 21:39:12 miod Exp $	*/
/*	$NetBSD: bus_dma.c,v 1.5 1999/11/13 00:32:20 thorpej Exp $	*/

/*-
 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * bus_dma routines for vax. File copied from arm32/bus_dma.c.
 * NetBSD: bus_dma.c,v 1.11 1998/09/21 22:53:35 thorpej Exp
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/vnode.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#define _VAX_BUS_DMA_PRIVATE
#include <machine/bus.h>

#include <machine/ka43.h>
#include <machine/sid.h>

extern	vaddr_t virtual_avail;

int	_bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
	    bus_size_t, struct proc *, int, paddr_t *, int *, int);
int	_bus_dma_inrange(bus_dma_segment_t *, int, bus_addr_t);
int	_bus_dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t,
	    bus_size_t, bus_dma_segment_t*, int, int *, int, vaddr_t, vaddr_t);
/*
 * Common function for DMA map creation.  May be called by bus-specific
 * DMA map creation functions.
 */
int
_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
	bus_dma_tag_t t;
	bus_size_t size;
	int nsegments;
	bus_size_t maxsegsz;
	bus_size_t boundary;
	int flags;
	bus_dmamap_t *dmamp;
{
	struct vax_bus_dmamap *map;
	void *mapstore;
	size_t mapsize;

#ifdef DEBUG_DMA
	printf("dmamap_create: t=%p size=%lx nseg=%x msegsz=%lx boundary=%lx flags=%x\n",
	    t, size, nsegments, maxsegsz, boundary, flags);
#endif	/* DEBUG_DMA */

	/*
	 * Allocate and initialize the DMA map.  The end of the map
	 * is a variable-sized array of segments, so we allocate enough
	 * room for them in one shot.
	 *
	 * Note we don't preserve the WAITOK or NOWAIT flags.  Preservation
	 * of ALLOCNOW notifies others that we've reserved these resources,
	 * and they are not to be freed.
	 *
	 * The bus_dmamap_t includes one bus_dma_segment_t, hence
	 * the (nsegments - 1).
	 */
	mapsize = sizeof(struct vax_bus_dmamap) +
	    (sizeof(bus_dma_segment_t) * (nsegments - 1));
	if ((mapstore = malloc(mapsize, M_DEVBUF, (flags & BUS_DMA_NOWAIT) ?
	    (M_NOWAIT | M_ZERO) : (M_WAITOK | M_ZERO))) == NULL)
		return (ENOMEM);

	map = (struct vax_bus_dmamap *)mapstore;
	map->_dm_size = size;
	map->_dm_segcnt = nsegments;
	map->_dm_maxsegsz = maxsegsz;
	map->_dm_boundary = boundary;
	map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
	map->dm_mapsize = 0;		/* no valid mappings */
	map->dm_nsegs = 0;

	*dmamp = map;
#ifdef DEBUG_DMA
	printf("dmamap_create:map=%p\n", map);
#endif	/* DEBUG_DMA */
	return (0);
}

/*
 * Common function for DMA map destruction.  May be called by bus-specific
 * DMA map destruction functions.
 */
void
_bus_dmamap_destroy(t, map)
	bus_dma_tag_t t;
	bus_dmamap_t map;
{
	size_t mapsize;

#ifdef DEBUG_DMA
	printf("dmamap_destroy: t=%p map=%p\n", t, map);
#endif	/* DEBUG_DMA */
#ifdef DIAGNOSTIC
	if (map->dm_nsegs > 0)
		printf("bus_dmamap_destroy() called for map with valid mappings\n");
#endif	/* DIAGNOSTIC */
	mapsize = sizeof(struct vax_bus_dmamap) +
	    (sizeof(bus_dma_segment_t) * (map->_dm_segcnt - 1));
	free(map, M_DEVBUF, mapsize);
}

/*
 * Common function for loading a DMA map with a linear buffer.  May
 * be called by bus-specific DMA map load functions.
 */
int
_bus_dmamap_load(t, map, buf, buflen, p, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	void *buf;
	bus_size_t buflen;
	struct proc *p;
	int flags;
{
	paddr_t lastaddr;
	int seg, error;

#ifdef DEBUG_DMA
	printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
	    t, map, buf, buflen, p, flags);
#endif	/* DEBUG_DMA */

	/*
	 * Make sure that on error condition we return "no valid mappings".
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;

	if (buflen > map->_dm_size)
		return (EINVAL);

	seg = 0;
	error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
	    &lastaddr, &seg, 1);
	if (error == 0) {
		map->dm_mapsize = buflen;
		map->dm_nsegs = seg + 1;
	}
#ifdef DEBUG_DMA
	printf("dmamap_load: error=%d\n", error);
#endif	/* DEBUG_DMA */
	return (error);
}

/*
 * Like _bus_dmamap_load(), but for mbufs.
 */
int
_bus_dmamap_load_mbuf(t, map, m0, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct mbuf *m0;
	int flags;
{
	paddr_t lastaddr;
	int seg, error, first;
	struct mbuf *m;

#ifdef DEBUG_DMA
	printf("dmamap_load_mbuf: t=%p map=%p m0=%p f=%d\n",
	    t, map, m0, flags);
#endif	/* DEBUG_DMA */

	/*
	 * Make sure that on error condition we return "no valid mappings."
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;

#ifdef DIAGNOSTIC
	if ((m0->m_flags & M_PKTHDR) == 0)
		panic("_bus_dmamap_load_mbuf: no packet header");
#endif	/* DIAGNOSTIC */

	if (m0->m_pkthdr.len > map->_dm_size)
		return (EINVAL);

	first = 1;
	seg = 0;
	error = 0;
	for (m = m0; m != NULL && error == 0; m = m->m_next) {
		if (m->m_len == 0)
			continue;
		error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
		    NULL, flags, &lastaddr, &seg, first);
		first = 0;
	}
	if (error == 0) {
		map->dm_mapsize = m0->m_pkthdr.len;
		map->dm_nsegs = seg + 1;
	}
#ifdef DEBUG_DMA
	printf("dmamap_load_mbuf: error=%d\n", error);
#endif	/* DEBUG_DMA */
	return (error);
}

/*
 * Like _bus_dmamap_load(), but for uios.
 */
int
_bus_dmamap_load_uio(t, map, uio, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct uio *uio;
	int flags;
{
	paddr_t lastaddr;
	int seg, i, error, first;
	bus_size_t minlen, resid;
	struct proc *p = NULL;
	struct iovec *iov;
	caddr_t addr;

	/*
	 * Make sure that on error condition we return "no valid mappings."
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;

	resid = uio->uio_resid;
	iov = uio->uio_iov;

	if (uio->uio_segflg == UIO_USERSPACE) {
		p = uio->uio_procp;
#ifdef DIAGNOSTIC
		if (p == NULL)
			panic("_bus_dmamap_load_uio: USERSPACE but no proc");
#endif
	}

	first = 1;
	seg = 0;
	error = 0;
	for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
		/*
		 * Now at the first iovec to load.  Load each iovec
		 * until we have exhausted the residual count.
		 */
		minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
		addr = (caddr_t)iov[i].iov_base;

		error = _bus_dmamap_load_buffer(t, map, addr, minlen,
		    p, flags, &lastaddr, &seg, first);
		first = 0;

		resid -= minlen;
	}
	if (error == 0) {
		map->dm_mapsize = uio->uio_resid;
		map->dm_nsegs = seg + 1;
	}
	return (error);
}

/*
 * Like _bus_dmamap_load(), but for raw memory allocated with
 * bus_dmamem_alloc().
 */
int
_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_dma_segment_t *segs;
	int nsegs;
	bus_size_t size;
	int flags;
{

	panic("_bus_dmamap_load_raw: not implemented");
}

/*
 * Common function for unloading a DMA map.  May be called by
 * bus-specific DMA map unload functions.
 */
void
_bus_dmamap_unload(t, map)
	bus_dma_tag_t t;
	bus_dmamap_t map;
{

#ifdef DEBUG_DMA
	printf("dmamap_unload: t=%p map=%p\n", t, map);
#endif	/* DEBUG_DMA */

	/*
	 * No resources to free; just mark the mappings as
	 * invalid.
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;
}

/*
 * Common function for DMA map synchronization.  May be called
 * by bus-specific DMA map synchronization functions.
 */
void
_bus_dmamap_sync(t, map, offset, len, ops)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_addr_t offset;
	bus_size_t len;
	int ops;
{
#ifdef DEBUG_DMA
	printf("dmamap_sync: t=%p map=%p offset=%lx len=%lx ops=%x\n",
	    t, map, offset, len, ops);
#endif	/* DEBUG_DMA */
	/*
	 * A vax only has snoop-cache, so this routine is a no-op.
	 */
	return;
}

/*
 * Common function for DMA-safe memory allocation.  May be called
 * by bus-specific DMA memory allocation functions.
 */

int
_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
	bus_dma_tag_t t;
	bus_size_t size, alignment, boundary;
	bus_dma_segment_t *segs;
	int nsegs;
	int *rsegs;
	int flags;
{
	int error;

	error = _bus_dmamem_alloc_range(t, size, alignment, boundary,
	    segs, nsegs, rsegs, flags, 0, -1);
	return(error);
}

/*
 * Common function for freeing DMA-safe memory.  May be called by
 * bus-specific DMA memory free functions.
 */
void
_bus_dmamem_free(t, segs, nsegs)
	bus_dma_tag_t t;
	bus_dma_segment_t *segs;
	int nsegs;
{
	struct vm_page *m;
	bus_addr_t addr;
	struct pglist mlist;
	int curseg;

#ifdef DEBUG_DMA
	printf("dmamem_free: t=%p segs=%p nsegs=%x\n", t, segs, nsegs);
#endif	/* DEBUG_DMA */

	/*
	 * Build a list of pages to free back to the VM system.
	 */
	TAILQ_INIT(&mlist);
	for (curseg = 0; curseg < nsegs; curseg++) {
		for (addr = segs[curseg].ds_addr;
		    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
		    addr += PAGE_SIZE) {
			m = PHYS_TO_VM_PAGE(addr);
			TAILQ_INSERT_TAIL(&mlist, m, pageq);
		}
	}
	uvm_pglistfree(&mlist);
}

/*
 * Common function for mapping DMA-safe memory.  May be called by
 * bus-specific DMA memory map functions.
 */
int
_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
	bus_dma_tag_t t;
	bus_dma_segment_t *segs;
	int nsegs;
	size_t size;
	caddr_t *kvap;
	int flags;
{
	vaddr_t va, sva;
	size_t ssize;
	bus_addr_t addr;
	int curseg, error;
	const struct kmem_dyn_mode *kd;

	/*
	 * Special case (but common):
	 * If there is only one physical segment then the already-mapped
	 * virtual address is returned, since all physical memory is already
	 * in the beginning of kernel virtual memory.
	 */
	if (nsegs == 1) {
		*kvap = (caddr_t)(segs[0].ds_addr | KERNBASE);
		/*
		 * KA43 (3100/m76) must have its DMA-safe memory accessed
		 * through DIAGMEM. Remap it here.
		 */
		if (vax_boardtype == VAX_BTYP_43) {
			pmap_map((vaddr_t)*kvap, segs[0].ds_addr|KA43_DIAGMEM,
			    (segs[0].ds_addr|KA43_DIAGMEM) + size,
			    PROT_READ | PROT_WRITE);
		}
		return 0;
	}
	size = round_page(size);
	kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok;
	va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd);
	if (va == 0)
		return (ENOMEM);

	*kvap = (caddr_t)va;

	sva = va;
	ssize = size;
	for (curseg = 0; curseg < nsegs; curseg++) {
		for (addr = segs[curseg].ds_addr;
		    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
		    addr += NBPG, va += NBPG, size -= NBPG) {
			if (size == 0)
				panic("_bus_dmamem_map: size botch");
			if (vax_boardtype == VAX_BTYP_43)
				addr |= KA43_DIAGMEM;
			error = pmap_enter(pmap_kernel(), va, addr,
			    PROT_READ | PROT_WRITE,
			    PROT_READ | PROT_WRITE | PMAP_WIRED | PMAP_CANFAIL);
			if (error) {
				pmap_update(pmap_kernel());
				km_free((void *)sva, ssize, &kv_any, &kp_none);
				return (error);
			}
		}
	}
	pmap_update(pmap_kernel());
	return (0);
}

/*
 * Common function for unmapping DMA-safe memory.  May be called by
 * bus-specific DMA memory unmapping functions.
 */
void
_bus_dmamem_unmap(t, kva, size)
	bus_dma_tag_t t;
	caddr_t kva;
	size_t size;
{

#ifdef DEBUG_DMA
	printf("dmamem_unmap: t=%p kva=%p size=%x\n", t, kva, size);
#endif	/* DEBUG_DMA */
#ifdef DIAGNOSTIC
	if ((u_long)kva & PGOFSET)
		panic("_bus_dmamem_unmap");
#endif	/* DIAGNOSTIC */

	/* Avoid free'ing if not mapped */
	if (kva >= (caddr_t)virtual_avail)
		km_free(kva, round_page(size), &kv_any, &kp_none);
}

/*
 * Common function for mmap(2)'ing DMA-safe memory.  May be called by
 * bus-specific DMA mmap(2)'ing functions.
 */
paddr_t
_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
	bus_dma_tag_t t;
	bus_dma_segment_t *segs;
	int nsegs;
	off_t off;
	int prot, flags;
{
	int i;

	for (i = 0; i < nsegs; i++) {
#ifdef DIAGNOSTIC
		if (off & PGOFSET)
			panic("_bus_dmamem_mmap: offset unaligned");
		if (segs[i].ds_addr & PGOFSET)
			panic("_bus_dmamem_mmap: segment unaligned");
		if (segs[i].ds_len & PGOFSET)
			panic("_bus_dmamem_mmap: segment size not multiple"
			    " of page size");
#endif	/* DIAGNOSTIC */
		if (off >= segs[i].ds_len) {
			off -= segs[i].ds_len;
			continue;
		}

		return (segs[i].ds_addr + off);
	}

	/* Page not found. */
	return (-1);
}

/**********************************************************************
 * DMA utility functions
 **********************************************************************/

/*
 * Utility function to load a linear buffer.  lastaddrp holds state
 * between invocations (for multiple-buffer loads).  segp contains
 * the starting segment on entrance, and the ending segment on exit.
 * first indicates if this is the first invocation of this function.
 */
int
_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	void *buf;
	bus_size_t buflen;
	struct proc *p;
	int flags;
	paddr_t *lastaddrp;
	int *segp;
	int first;
{
	bus_size_t sgsize;
	bus_addr_t curaddr, lastaddr, baddr, bmask;
	vaddr_t vaddr = (vaddr_t)buf;
	int seg;
	pmap_t pmap;

#ifdef DEBUG_DMA
	printf("_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d, 1st=%d)\n",
	    buf, buflen, flags, first);
#endif	/* DEBUG_DMA */

	if (p != NULL)
		pmap = p->p_vmspace->vm_map.pmap;
	else
		pmap = pmap_kernel();

	lastaddr = *lastaddrp;
	bmask  = ~(map->_dm_boundary - 1);

	for (seg = *segp; buflen > 0; ) {
		/*
		 * Get the physical address for this segment.
		 */
		pmap_extract(pmap, (vaddr_t)vaddr, &curaddr);
#if 0
		/*
		 * Make sure we're in an allowed DMA range.
		 */
		if (t->_ranges != NULL &&
		    _bus_dma_inrange(t->_ranges, t->_nranges, curaddr) == 0)
			return (EINVAL);
#endif

		/*
		 * Compute the segment size, and adjust counts.
		 */
		sgsize = NBPG - ((u_long)vaddr & PGOFSET);
		if (buflen < sgsize)
			sgsize = buflen;

		/*
		 * Make sure we don't cross any boundaries.
		 */
		if (map->_dm_boundary > 0) {
			baddr = (curaddr + map->_dm_boundary) & bmask;
			if (sgsize > (baddr - curaddr))
				sgsize = (baddr - curaddr);
		}

		/*
		 * Insert chunk into a segment, coalescing with
		 * previous segment if possible.
		 */
		if (first) {
			map->dm_segs[seg].ds_addr = curaddr;
			map->dm_segs[seg].ds_len = sgsize;
			first = 0;
		} else {
			if (curaddr == lastaddr &&
			    (map->dm_segs[seg].ds_len + sgsize) <=
			     map->_dm_maxsegsz &&
			    (map->_dm_boundary == 0 ||
			     (map->dm_segs[seg].ds_addr & bmask) ==
			     (curaddr & bmask)))
				map->dm_segs[seg].ds_len += sgsize;
			else {
				if (++seg >= map->_dm_segcnt)
					break;
				map->dm_segs[seg].ds_addr = curaddr;
				map->dm_segs[seg].ds_len = sgsize;
			}
		}

		lastaddr = curaddr + sgsize;
		vaddr += sgsize;
		buflen -= sgsize;
	}

	*segp = seg;
	*lastaddrp = lastaddr;

	/*
	 * Did we fit?
	 */
	if (buflen != 0)
		return (EFBIG);		/* XXX better return value here? */
	return (0);
}

/*
 * Check to see if the specified page is in an allowed DMA range.
 */
int
_bus_dma_inrange(ranges, nranges, curaddr)
	bus_dma_segment_t *ranges;
	int nranges;
	bus_addr_t curaddr;
{
	bus_dma_segment_t *ds;
	int i;

	for (i = 0, ds = ranges; i < nranges; i++, ds++) {
		if (curaddr >= ds->ds_addr &&
		    round_page(curaddr) <= (ds->ds_addr + ds->ds_len))
			return (1);
	}

	return (0);
}

/*
 * Allocate physical memory from the given physical address range.
 * Called by DMA-safe memory allocation methods.
 */
int
_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
    flags, low, high)
	bus_dma_tag_t t;
	bus_size_t size, alignment, boundary;
	bus_dma_segment_t *segs;
	int nsegs;
	int *rsegs;
	int flags;
	vaddr_t low;
	vaddr_t high;
{
	paddr_t curaddr, lastaddr;
	struct vm_page *m;
	struct pglist mlist;
	int curseg, error, plaflag;

#ifdef DEBUG_DMA
	printf("alloc_range: t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x lo=%lx hi=%lx\n",
	    t, size, alignment, boundary, segs, nsegs, rsegs, flags, low, high);
#endif	/* DEBUG_DMA */

	/* Always round the size. */
	size = round_page(size);

	/*
	 * Allocate pages from the VM system.
	 */
	plaflag = flags & BUS_DMA_NOWAIT ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK;
	if (flags & BUS_DMA_ZERO)
		plaflag |= UVM_PLA_ZERO;

	TAILQ_INIT(&mlist);
	error = uvm_pglistalloc(size, low, high, alignment, boundary,
	    &mlist, nsegs, plaflag);
	if (error)
		return (error);

	/*
	 * Compute the location, size, and number of segments actually
	 * returned by the VM code.
	 */
	m = TAILQ_FIRST(&mlist);
	curseg = 0;
	lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
	segs[curseg].ds_len = PAGE_SIZE;
#ifdef DEBUG_DMA
		printf("alloc: page %lx\n", lastaddr);
#endif	/* DEBUG_DMA */
	m = TAILQ_NEXT(m, pageq);

	for (; m != NULL; m = TAILQ_NEXT(m, pageq)) {
		curaddr = VM_PAGE_TO_PHYS(m);
#ifdef DIAGNOSTIC
		if (curaddr < low || curaddr >= high) {
			printf("vm_page_alloc_memory returned non-sensical"
			    " address 0x%lx\n", curaddr);
			panic("_bus_dmamem_alloc_range");
		}
#endif	/* DIAGNOSTIC */
#ifdef DEBUG_DMA
		printf("alloc: page %lx\n", curaddr);
#endif	/* DEBUG_DMA */
		if (curaddr == (lastaddr + PAGE_SIZE))
			segs[curseg].ds_len += PAGE_SIZE;
		else {
			curseg++;
			segs[curseg].ds_addr = curaddr;
			segs[curseg].ds_len = PAGE_SIZE;
		}
		lastaddr = curaddr;
	}

	*rsegs = curseg + 1;

	return (0);
}

/*
 * "generic" DMA struct, nothing special.
 */
struct vax_bus_dma_tag vax_bus_dma_tag = {
	NULL,
	0,
	0,
	0,
	NULL,
	_bus_dmamap_create,
	_bus_dmamap_destroy,
	_bus_dmamap_load,
	_bus_dmamap_load_mbuf,
	_bus_dmamap_load_uio,
	_bus_dmamap_load_raw,
	_bus_dmamap_unload,
	_bus_dmamap_sync,
	_bus_dmamem_alloc,
	_bus_dmamem_free,
	_bus_dmamem_map,
	_bus_dmamem_unmap,
	_bus_dmamem_mmap,
};


code:
/*	$OpenBSD: bus_mem.c,v 1.7 2009/12/26 14:45:36 miod Exp $	*/
/*	$NetBSD: bus_mem.c,v 1.8 2000/06/29 07:14:23 mrg Exp $ */
/*
 * Copyright (c) 1998 Matt Thomas
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/pmap.h>
#include <machine/bus.h>
#include <machine/intr.h>

int	 vax_mem_bus_space_map(void *, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
void	 vax_mem_bus_space_unmap(void *, bus_space_handle_t, bus_size_t);
int	 vax_mem_bus_space_subregion(void *, bus_space_handle_t, bus_size_t,
	    bus_size_t, bus_space_handle_t *);
int	 vax_mem_bus_space_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t,
	    bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *);
void	 vax_mem_bus_space_free(void *, bus_space_handle_t, bus_size_t);
void	*vax_mem_bus_space_vaddr(void *, bus_space_handle_t);

int
vax_mem_bus_space_map(void *t, bus_addr_t pa, bus_size_t size, int flags,
    bus_space_handle_t *bshp)
{
	vaddr_t va;

	size += (pa & VAX_PGOFSET);	/* have to include the byte offset */
	va = uvm_km_valloc(kernel_map, size);
	if (va == 0)
		return (ENOMEM);

	*bshp = (bus_space_handle_t)(va + (pa & VAX_PGOFSET));

	ioaccess(va, pa, (size + VAX_NBPG - 1) >> VAX_PGSHIFT);

	return 0;
}

int
vax_mem_bus_space_subregion(void *t, bus_space_handle_t h, bus_size_t o,
    bus_size_t s, bus_space_handle_t *hp)
{
	*hp = h + o;
	return (0);
}

void
vax_mem_bus_space_unmap(void *t, bus_space_handle_t h, bus_size_t size)
{
	u_long va = trunc_page(h);
	u_long endva = round_page(h + size);

        /*
         * Free the kernel virtual mapping.
         */
	iounaccess(va, size >> VAX_PGSHIFT);
	uvm_km_free(kernel_map, va, endva - va);
}

int
vax_mem_bus_space_alloc(void *t, bus_addr_t rs, bus_addr_t re, bus_size_t s,
    bus_size_t a, bus_size_t b, int f, bus_addr_t *ap, bus_space_handle_t *hp)
{
	panic("vax_mem_bus_alloc not implemented");
}

void
vax_mem_bus_space_free(void *t, bus_space_handle_t h, bus_size_t s)
{
	panic("vax_mem_bus_free not implemented");
}

void *
vax_mem_bus_space_vaddr(void *t, bus_space_handle_t h)
{
	return ((void *)h);
}

struct vax_bus_space vax_mem_bus_space = {
	NULL,
	vax_mem_bus_space_map,
	vax_mem_bus_space_unmap,
	vax_mem_bus_space_subregion,
	vax_mem_bus_space_alloc,
	vax_mem_bus_space_free,
	vax_mem_bus_space_vaddr
};

license: unknown


code:
/*	$OpenBSD: clock.c,v 1.25 2015/02/07 00:09:09 miod Exp $	 */
/*	$NetBSD: clock.c,v 1.35 2000/06/04 06:16:58 matt Exp $	 */
/*
 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/timetc.h>

#include <dev/clock_subr.h>

#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/uvax.h>

struct evcount clock_intrcnt;
uint32_t icr_count;

#if defined(VAX46) || defined(VAX48)
u_int	vax_diagtmr_get_tc(struct timecounter *);

/*
 * This counter is only reliable in millisecond units.  See comments in
 * vax_diagtmr_get_tc() for details.
 */
struct timecounter vax_diagtmr_tc = {
	.tc_get_timecount = vax_diagtmr_get_tc,
	.tc_counter_mask = 0xffff,	/* 16 bits */
	.tc_frequency = 1000,		/* 1kHz */
	/* tc_name will be filled in */
	.tc_quality = 100
};
#endif

#ifdef VXT
u_int	vax_vxt_get_tc(struct timecounter *);

struct timecounter vax_vxt_tc = {
	.tc_get_timecount = vax_vxt_get_tc,
	.tc_counter_mask = 0xffffffff,
	.tc_frequency = 100,		/* 100Hz */
	.tc_name = "vxt",
	.tc_quality = 0
};
#endif

u_int	vax_icr_get_tc(struct timecounter *);

struct timecounter vax_icr_tc = {
	.tc_get_timecount = vax_icr_get_tc,
	.tc_counter_mask = 0xffffffff,
	.tc_frequency = 1000000,	/* 1MHz */
	.tc_name = "icr",
	.tc_quality = 100
};

/*
 * Sets year to the year in fs_time and then calculates the number of
 * 100th of seconds in the current year and saves that info in year_len.
 * fs_time contains the time set in the superblock in the root filesystem.
 * If the clock is started, it then checks if the time is valid
 * compared with the time in fs_time. If the clock is stopped, an
 * alert is printed and the time is temporary set to the time in fs_time.
 */

void
inittodr(time_t fs_time)
{
	int rv, deltat;
	struct timespec ts;

	rv = (*dep_call->cpu_clkread)(&ts, fs_time);
	if (rv != 0) {
		/* No useable information from system clock */
		ts.tv_sec = fs_time;
		ts.tv_nsec = 0;
		resettodr();
	} else {
		/* System clock OK, no warning if we don't want to. */
		deltat = ts.tv_sec - fs_time;

		if (deltat < 0)
			deltat = -deltat;
		if (deltat >= 2 * SEC_PER_DAY) {
			printf("clock has %s %d days",
			    ts.tv_sec < fs_time ? "lost" : "gained",
			    deltat / SEC_PER_DAY);
			rv = EINVAL;
		}
	}

	if (rv != 0)
		printf(" -- CHECK AND RESET THE DATE!\n");

	tc_setclock(&ts);
}

/*
 * Resettodr restores the time of day hardware after a time change.
 */

void
resettodr()
{
	(*dep_call->cpu_clkwrite)();
}

/*
 * A delayloop that delays about the number of milliseconds that is
 * given as argument.
 */
void
delay(int i)
{
	asm ("1: sobgtr %0, 1b" : : "r" (dep_call->cpu_vups * i));
}

/*
 * On all VAXen there are a microsecond clock that should
 * be used for interval interrupts. We have to be wary of the few CPUs
 * which don't implement the ICR interval register.
 */
void
cpu_initclocks()
{
	switch (vax_boardtype) {
#ifdef VAX46
	/* VAXstation 4000/60: no ICR register but a specific timer */
	case VAX_BTYP_46:
	    {
		extern struct vs_cpu *ka46_cpu;

		vax_diagtmr_tc.tc_priv = ka46_cpu;
		vax_diagtmr_tc.tc_name = "KA46";
		tc_init(&vax_diagtmr_tc);
	    }
		break;
#endif
#ifdef VAX48
	/* VAXstation 4000/VLC: no ICR register but a specific timer */
	case VAX_BTYP_48:
	    {
		extern struct vs_cpu *ka48_cpu;

		vax_diagtmr_tc.tc_priv = ka48_cpu;
		vax_diagtmr_tc.tc_name = "KA48";
		tc_init(&vax_diagtmr_tc);
	    }
		break;
#endif
#ifdef VXT
	/* VXT2000: neither NICR nor ICR registers, no known other timer. */
	case VAX_BTYP_VXT:
		tc_init(&vax_vxt_tc);
		break;
#endif
	/* all other systems: NICR+ICR registers implementing a 1MHz timer. */
	default:
		tc_init(&vax_icr_tc);
		break;
	}

	evcount_attach(&clock_intrcnt, "clock", NULL);
	if (vax_boardtype != VAX_BTYP_VXT)
		mtpr(-tick, PR_NICR); /* Load in count register */
	mtpr(ICCS_ERR | ICCS_OFLOW | ICCS_INTENA | ICCS_RESET | ICCS_RUN,
	    PR_ICCS); /* Reset errors, start clock and enable interrupt */
}

void
icr_hardclock(struct clockframe *cf)
{
	icr_count += 10000;	/* tick */
	hardclock(cf);
}

/*
 * There are two types of real-time battery-backed up clocks on
 * VAX computers, one with a register that counts up every 1/100 second,
 * one with a clock chip that delivers time. For the register clock
 * we have a generic version, and for the chip clock there are
 * support routines for time conversion.
 */
/*
 * Converts a year to corresponding number of ticks.
 */
int
yeartonum(int y)
{
	int n;

	for (n = 0, y -= 1; y > 69; y--)
		n += SECPERYEAR(y);
	return n;
}

/*
 * Converts tick number to a year 70 ->
 */
int
numtoyear(int num)
{
	int y = 70, j;
	while (num >= (j = SECPERYEAR(y))) {
		y++;
		num -= j;
	}
	return y;
}

#if VAX650 || VAX660 || VAX670 || VAX680 || VAX53
/*
 * Reads the TODR register; returns 0 if a valid time has been found, EINVAL
 * otherwise.  The year is based on the argument year; the TODR doesn't hold
 * years.
 */
int
generic_clkread(struct timespec *ts, time_t base)
{
	uint32_t klocka = mfpr(PR_TODR);

	/*
	 * Sanity check.
	 */
	if (klocka < TODRBASE) {
		if (klocka == 0)
			printf("TODR stopped");
		else
			printf("TODR too small");
		return EINVAL;
	}

	ts->tv_sec =
	    yeartonum(numtoyear(base)) + (klocka - TODRBASE) / 100;
	ts->tv_nsec = 0;
	return 0;
}

/*
 * Takes the current system time and writes it to the TODR.
 */
void
generic_clkwrite()
{
	uint32_t tid = time_second, bastid;

	bastid = tid - yeartonum(numtoyear(tid));
	mtpr((bastid * 100) + TODRBASE, PR_TODR);
}
#endif

#if VAX630 || VAX410 || VAX43 || VAX46 || VAX48 || VAX49

volatile short *clk_page;	/* where the chip is mapped in virtual memory */
int	clk_adrshift;	/* how much to multiply the in-page address with */
int	clk_tweak;	/* Offset of time into word. */

#define	REGPEEK(off)	(clk_page[off << clk_adrshift] >> clk_tweak)
#define	REGPOKE(off, v)	(clk_page[off << clk_adrshift] = ((v) << clk_tweak))

int
chip_clkread(struct timespec *ts, time_t base)
{
	struct clock_ymdhms c;
	int timeout = 1<<15, s;

#ifdef DIAGNOSTIC
	if (clk_page == 0)
		panic("trying to use unset chip clock page");
#endif

	if ((REGPEEK(CSRD_OFF) & CSRD_VRT) == 0) {
		printf("WARNING: TOY clock not marked valid");
		return EINVAL;
	}
	while (REGPEEK(CSRA_OFF) & CSRA_UIP)
		if (--timeout == 0) {
			printf ("TOY clock timed out");
			return EINVAL;
		}

	s = splhigh();
	c.dt_year = ((u_char)REGPEEK(YR_OFF)) + 1970;
	c.dt_mon = REGPEEK(MON_OFF);
	c.dt_day = REGPEEK(DAY_OFF);
	c.dt_wday = REGPEEK(WDAY_OFF);
	c.dt_hour = REGPEEK(HR_OFF);
	c.dt_min = REGPEEK(MIN_OFF);
	c.dt_sec = REGPEEK(SEC_OFF);
	splx(s);

	ts->tv_sec = clock_ymdhms_to_secs(&c);
	ts->tv_nsec = 0;
	return 0;
}

void
chip_clkwrite()
{
	struct clock_ymdhms c;

#ifdef DIAGNOSTIC
	if (clk_page == 0)
		panic("trying to use unset chip clock page");
#endif

	REGPOKE(CSRB_OFF, CSRB_SET);

	clock_secs_to_ymdhms(time_second, &c);

	REGPOKE(YR_OFF, ((u_char)(c.dt_year - 1970)));
	REGPOKE(MON_OFF, c.dt_mon);
	REGPOKE(DAY_OFF, c.dt_day);
	REGPOKE(WDAY_OFF, c.dt_wday);
	REGPOKE(HR_OFF, c.dt_hour);
	REGPOKE(MIN_OFF, c.dt_min);
	REGPOKE(SEC_OFF, c.dt_sec);

	REGPOKE(CSRB_OFF, CSRB_DM|CSRB_24);
};
#endif

#if defined(VAX46) || defined(VAX48)
u_int
vax_diagtmr_get_tc(struct timecounter *tc)
{
	/*
	 * The diagnostic timer runs at about 1024kHz.
	 * The microsecond counter counts from 0 to 1023 inclusive (so it
	 * really is a 1/1024th millisecond counter) and increments the
	 * millisecond counter, which is a free-running 16 bit counter.
	 *
	 * To compensate for the timer not running at exactly 1024kHz,
	 * the microsecond counter is reset (to zero) every clock interrupt,
	 * i.e. every 10 millisecond.
	 *
	 * Without resetting the microsecond counter, experiments show that,
	 * on KA48, the millisecond counter increments of 960 in a second,
	 * instead of the expected 1000 (i.e. a 24/25 ratio).  But resetting
	 * the microsecond counter (which does not affect the millisecond
	 * counter value) ought to make it __slower__ - who can explain
	 * this behaviour?
	 *
	 * Because we reset the ``binary microsecond'' counter and can not
	 * afford time moving backwards, we only return the millisecond
	 * counter here.
	 */
	struct vs_cpu *vscpu;

	vscpu = (struct vs_cpu *)tc->tc_priv;
	return *(volatile uint16_t *)&vscpu->vc_diagtimm;
}
#endif

#ifdef VXT
u_int
vax_vxt_get_tc(struct timecounter *tc)
{
	return (u_int)clock_intrcnt.ec_count;
}
#endif

u_int
vax_icr_get_tc(struct timecounter *tc)
{
	return icr_count + (u_int)(tick + (int)mfpr(PR_ICR));
}


code:
/*	$OpenBSD: conf.c,v 1.70 2014/10/09 03:59:59 tedu Exp $ */
/*	$NetBSD: conf.c,v 1.44 1999/10/27 16:38:54 ragge Exp $	*/

/*-
 * Copyright (c) 1982, 1986 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)conf.c	7.18 (Berkeley) 5/9/91
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/conf.h>
#include <sys/vnode.h>

#include "mt.h"
bdev_decl(mt);

#include "rd.h"

#include "ra.h"
bdev_decl(ra);
bdev_decl(rx);

#include "vnd.h"

#include "hdc.h"
bdev_decl(hd);
bdev_decl(ry);

#include "sd.h"
#include "st.h"
#include "cd.h"

#include "ksyms.h"

struct bdevsw	bdevsw[] =
{
	bdev_notdef(),			/* 0 */
	bdev_notdef(),			/* 1 */
	bdev_notdef(),			/* 2 */
	bdev_notdef(),			/* 3 */
	bdev_swap_init(1,sw),		/* 4: swap pseudo-device */
	bdev_notdef(),			/* 5 */
	bdev_notdef(),			/* 6 */
	bdev_notdef(),			/* 7 */
	bdev_notdef(),			/* 8 */
	bdev_disk_init(NRA,ra),		/* 9: MSCP disk */
	bdev_notdef(),			/* 10 */
	bdev_notdef(),			/* 11 */
	bdev_disk_init(NRX,rx),		/* 12: RX?? on MSCP */
	bdev_notdef(),			/* 13 */
	bdev_notdef(),			/* 14 */
	bdev_tape_init(NMT,mt),		/* 15: MSCP tape */
	bdev_notdef(),			/* 16: was: KDB50/RA?? */
	bdev_notdef(),			/* 17: was: concatenated disk driver */
	bdev_disk_init(NVND,vnd),	/* 18: vnode disk driver */
	bdev_disk_init(NHD,hd),		/* 19: VS3100 ST506 disk */
	bdev_disk_init(NSD,sd),		/* 20: SCSI disk */
	bdev_tape_init(NST,st),		/* 21: SCSI tape */
	bdev_disk_init(NCD,cd),		/* 22: SCSI CD-ROM */
	bdev_disk_init(NRD,rd),		/* 23: ram disk driver */
	bdev_disk_init(NRY,ry),		/* 24: VS3100 floppy */
	bdev_notdef(),			/* 25 was: RAIDframe disk driver */
};
int	nblkdev = nitems(bdevsw);

/*
 * Console routines for VAX console.
 */
#include <dev/cons.h>

cons_decl(dz);
cons_decl(gen);
cons_decl(qsc);
cons_decl(ws);

#include "dz.h"
#include "qsc.h"
#include "wsdisplay.h"
#include "wskbd.h"

struct	consdev constab[]={
#if VAX650 || VAX630 || VAX660 || VAX670 || VAX680
#define NGEN	1
	cons_init(gen), /* Generic console type; mtpr/mfpr */
#else
#define NGEN	0
#endif
#if VAX410 || VAX43 || VAX46 || VAX48 || VAX49 || VAX53 || VAX60
#if NDZ > 0
	cons_init(dz),	/* DZ11-like serial console on VAXstations */
#endif
#endif
#ifdef VXT
#if NQSC > 0
	cons_init(qsc),	/* SC26C94 serial console on VXT2000 */
#endif
#endif
#if NWSDISPLAY > 0 || NWSKBD > 0
	cons_init(ws),	/* any other frame buffer console */
#endif

#ifdef notyet
/* We may not always use builtin console, sometimes RD */
	{ hdcnprobe, hdcninit, hdcngetc, hdcnputc },
#endif
	{ 0 }
};

#define mmread	mmrw
#define mmwrite mmrw
cdev_decl(mm);
#include "bio.h"
#include "pty.h"

cdev_decl(mt);
cdev_decl(ra);
cdev_decl(gencn);
cdev_decl(rx);
cdev_decl(hd);
cdev_decl(ry);

cdev_decl(qsc);

cdev_decl(dz);

#include "dhu.h"
cdev_decl(dhu);

#include "dl.h"
cdev_decl(dl);

#include "bpfilter.h"

#include "tun.h"
#include "ch.h"
#include "uk.h"

#include "wsdisplay.h"
#include "wskbd.h"
#include "wsmouse.h"

#include "pf.h"

#include "systrace.h"

#include "vscsi.h"
#include "pppx.h"
#include "audio.h"
#include "fuse.h"

struct cdevsw	cdevsw[] =
{
	cdev_cn_init(1,cn),		/* 0: virtual console */
	cdev_tty_init(NDZ,dz),		/* 1: DZ11 */
	cdev_ctty_init(1,ctty),		/* 2: controlling terminal */
	cdev_mm_init(1,mm),		/* 3: /dev/{null,mem,kmem,...} */
	cdev_notdef(),			/* 4 */
	cdev_notdef(),			/* 5 */
	cdev_notdef(),			/* 6 */
	cdev_notdef(),			/* 7 was /dev/drum */
	cdev_notdef(),			/* 8 */
	cdev_disk_init(NRA,ra),		/* 9: MSCP disk interface */
	cdev_notdef(),			/* 10 */
	cdev_notdef(),			/* 11 */
	cdev_notdef(),			/* 12 */
	cdev_notdef(),			/* 13 */
	cdev_notdef(),			/* 14 */
	cdev_notdef(),			/* 15 */
	cdev_notdef(),			/* 16 */
	cdev_notdef(),			/* 17 */
	cdev_notdef(),			/* 18 */
	cdev_notdef(),			/* 19 */
	cdev_tty_init(NPTY,pts),	/* 20: pseudo-tty slave */
	cdev_ptc_init(NPTY,ptc),	/* 21: pseudo-tty master */
	cdev_notdef(),			/* 22 */
	cdev_notdef(),			/* 23 */
	cdev_notdef(),			/* 24 */
	cdev_tty_init(NGEN,gencn),	/* 25: Generic console (mtpr...) */
	cdev_notdef(),			/* 26 */
	cdev_notdef(),			/* 27 */
	cdev_notdef(),			/* 28 was LKM */
	cdev_notdef(),			/* 29 */
	cdev_disk_init(NRX,rx),		/* 30: RX?? on MSCP */
	cdev_notdef(),			/* 31 */
	cdev_notdef(),			/* 32: RL01/02 on unibus */
	cdev_log_init(1,log),		/* 33: /dev/klog */
	cdev_tty_init(NDHU,dhu),	/* 34: DHU-11 */
	cdev_notdef(),			/* 35 */
	cdev_notdef(),			/* 36 */
	cdev_notdef(),			/* 37 */
	cdev_tape_init(NMT,mt),		/* 38: MSCP tape */
	cdev_notdef(),			/* 39 */
	cdev_notdef(),			/* 40 */
	cdev_notdef(),			/* 41 */
	cdev_pf_init(NPF,pf),		/* 42: packet filter */
	cdev_notdef(),			/* 43 */
	cdev_notdef(),			/* 44  was Datakit */
	cdev_notdef(),			/* 45  was Datakit */
	cdev_notdef(),			/* 46  was Datakit */
	cdev_notdef(),			/* 47 */
	cdev_tty_init(NQSC,qsc),	/* 48: SC26C94 on VXT2000 */
	cdev_systrace_init(NSYSTRACE,systrace),	/* 49: system call tracing */
	cdev_ksyms_init(NKSYMS,ksyms),	/* 50: Kernel symbols device */
	cdev_notdef(),			/* 51 */
	cdev_notdef(),			/* 52: was: KDB50/RA?? */
	cdev_fd_init(1,filedesc),	/* 53: file descriptor pseudo-device */
	cdev_notdef(),			/* 54: was: concatenated disk driver */
	cdev_disk_init(NVND,vnd),	/* 55: vnode disk driver */
	cdev_bpf_init(NBPFILTER,bpf),	/* 56: berkeley packet filter */
	cdev_tun_init(NTUN,tun),	/* 57: tunnel filter */
	cdev_disk_init(NHD,hd),		/* 58: HDC9224/RD?? */
	cdev_disk_init(NSD,sd),		/* 59: SCSI disk */
	cdev_tape_init(NST,st),		/* 60: SCSI tape */
	cdev_disk_init(NCD,cd),		/* 61: SCSI CD-ROM */
	cdev_disk_init(NRD,rd),		/* 62: memory disk driver */
	cdev_ch_init(NCH,ch),		/* 63: SCSI autochanger */
	cdev_notdef(),			/* 64 */
	cdev_uk_init(NUK,uk),		/* 65: SCSI unknown */
	cdev_tty_init(NDL,dl),		/* 66: DL11 */
	cdev_random_init(1,random),	/* 67: random data source */
	cdev_wsdisplay_init(NWSDISPLAY, wsdisplay), /* 68: frame buffers */
	cdev_mouse_init(NWSKBD, wskbd),	/* 69: keyboards */
	cdev_mouse_init(NWSMOUSE, wsmouse), /* 70: mice */
	cdev_disk_init(NRY,ry),		/* 71: VS floppy */
	cdev_bio_init(NBIO,bio),	/* 72: ioctl tunnel */
	cdev_notdef(),			/* 73 was: RAIDframe disk driver */
	cdev_notdef(),			/* 74 */
	cdev_ptm_init(NPTY,ptm),	/* 75: pseudo-tty ptm device */
	cdev_notdef(),			/* 76 */
	cdev_notdef(),			/* 77 */
	cdev_vscsi_init(NVSCSI,vscsi),	/* 78: vscsi */
	cdev_disk_init(1,diskmap),	/* 79: disk mapper */
	cdev_pppx_init(NPPPX,pppx),	/* 80: pppx */
	cdev_audio_init(NAUDIO,audio),	/* 81: /dev/audio */
	cdev_fuse_init(NFUSE,fuse),	/* 82: fuse */
};
int	nchrdev = nitems(cdevsw);

int	mem_no = 3;	/* major device number of memory special file */

/*
 * Swapdev is a fake device implemented
 * in sw.c used only internally to get to swstrategy.
 * It cannot be provided to the users, because the
 * swstrategy routine munches the b_dev and b_blkno entries
 * before calling the appropriate driver.  This would horribly
 * confuse, e.g. the hashing routines. Instead, /dev/drum is
 * provided as a character (raw) device.
 */
dev_t	swapdev = makedev(4, 0);

int	chrtoblktbl[] = {
	NODEV,	/* 0 */
	NODEV,	/* 1 */
	NODEV,	/* 2 */
	NODEV,	/* 3 */
	NODEV,	/* 4 */
	NODEV,	/* 5 */
	NODEV,	/* 6 */
	NODEV,	/* 7 */
	NODEV,	/* 8 */
	9,	/* 9 ra */
	NODEV,	/* 10 */
	NODEV,	/* 11 */
	NODEV,	/* 12 */
	NODEV,	/* 13 */
	NODEV,	/* 14 */
	NODEV,	/* 15 */
	NODEV,	/* 16 */
	NODEV,	/* 17 */
	NODEV,	/* 18 */
	NODEV,	/* 19 */
	NODEV,	/* 20 */
	NODEV,	/* 21 */
	NODEV,	/* 22 */
	NODEV,	/* 23 */
	NODEV,	/* 24 */
	NODEV,	/* 25 */
	NODEV,	/* 26 */
	NODEV,	/* 27 */
	NODEV,	/* 28 */
	NODEV,	/* 29 */
	12,	/* 30 rx */
	NODEV,	/* 31 */
	NODEV,	/* 32 */
	NODEV,	/* 33 */
	NODEV,	/* 34 */
	NODEV,	/* 35 */
	NODEV,	/* 36 */
	NODEV,	/* 37 */
	15,	/* 38 mt */
	NODEV,	/* 39 */
	NODEV,	/* 40 */
	NODEV,	/* 41 */
	NODEV,	/* 42 */
	NODEV,	/* 43 */
	NODEV,	/* 44 */
	NODEV,	/* 45 */
	NODEV,	/* 46 */
	NODEV,	/* 47 */
	NODEV,	/* 48 */
	NODEV,	/* 49 */
	NODEV,	/* 50 */
	NODEV,	/* 51 */
	NODEV,	/* 52 */
	NODEV,	/* 53 */
	NODEV,	/* 54 */
	18,	/* 55 vnd */
	NODEV,	/* 56 */
	NODEV,	/* 57 */
	19,	/* 58 hd */
	20,	/* 59 sd */
	21,	/* 60 st */
	22,	/* 61 cd */
	23,	/* 62 rd */
	NODEV,	/* 63 ch */
	NODEV,	/* 64 */
	NODEV,	/* 65 uk */
	NODEV,	/* 66 */
	NODEV,	/* 67 */
	NODEV,	/* 68 */
	NODEV,	/* 69 */
	NODEV,	/* 70 */
	24,	/* 71 ry */
	NODEV,	/* 72 */
	25,	/* 73 raid */
	NODEV,	/* 74 */
};
int nchrtoblktbl = nitems(chrtoblktbl);

/*
 * Returns true if dev is /dev/mem or /dev/kmem.
 */
int
iskmemdev(dev)
	dev_t dev;
{
	return (major(dev) == 3 && minor(dev) < 2);
}

/*
 * Returns true if dev is /dev/zero.
 * ?? Shall I use 12 as /dev/zero?
 */
int
iszerodev(dev)
	dev_t dev;
{

	return (major(dev) == 3 && minor(dev) == 12);
}

int getmajor(void *);	/* XXX used by dz_ibus and wscons, die die die */

int
getmajor(void *ptr)
{
	int i;

	for (i = 0; i < nchrdev; i++)
		if (cdevsw[i].d_open == ptr)
			return i;

	return (-1);
}

dev_t
getnulldev()
{
	return makedev(3, 2);
}


code:
/*	$OpenBSD: cvax.c,v 1.1 2008/08/18 23:07:26 miod Exp $	*/
/*	$NetBSD: ka650.c,v 1.25 2001/04/27 15:02:37 ragge Exp $	*/
/*
 * Copyright (c) 1988 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Mt. Xinu.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)ka650.c	7.7 (Berkeley) 12/16/90
 */

/*
 * CVAX-specific code.
 */

#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <uvm/uvm_extern.h>

#include <machine/cvax.h>
#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/psl.h>
#include <machine/mtpr.h>
#include <machine/sid.h>

struct	cvax_ssc *cvax_ssc_ptr;

/*
 * Machine Check descriptions
 */
const char *cvax_mcheck[] = {
	NULL,			/* 00 */
	"FPA proto err",	/* 01 */
	"FPA resv inst",	/* 02 */
	"FPA Ill Stat 2",	/* 03 */
	"FPA Ill Stat 1",	/* 04 */
	"PTE in P0, TB miss",	/* 05 */
	"PTE in P1, TB miss",	/* 06 */
	"PTE in P0, Mod",	/* 07 */
	"PTE in P1, Mod",	/* 08 */
	"Illegal intr IPL",	/* 09 */
	"MOVC state error",	/* 0a */

	"bus read error",	/* 80 */
	"SCB read error",	/* 81 */
	"bus write error",	/* 82 */
	"PCB write error"	/* 83 */
};

const char *
cvax_mchk_descr(int summary)
{
	if ((unsigned int)summary < 11)
		return cvax_mcheck[summary];

	if (summary >= 0x80 && summary <= 0x83)
		return cvax_mcheck[summary - 0x80 + 11];

	return NULL;
}

/*
 * CVAX Mailbox routines
 */

void
cvax_halt()
{
	cvax_ssc_ptr->ssc_cpmbx = CPMB_CVAX_DOTHIS | CPMB_CVAX_HALT;
	asm("halt");
}

void
cvax_reboot(arg)
	int arg;
{
	cvax_ssc_ptr->ssc_cpmbx = CPMB_CVAX_DOTHIS | CPMB_CVAX_REBOOT;
}


code:
/*	$OpenBSD: db_disasm.c,v 1.16 2008/08/15 22:41:02 miod Exp $ */
/*	$NetBSD: db_disasm.c,v 1.10 1998/04/13 12:10:27 ragge Exp $ */
/*
 * Copyright (c) 2002, Miodrag Vallat.
 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by
 * Bertram Barth.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/systm.h>

#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>

#include <vax/vax/db_disasm.h>

#ifdef VMS_MODE
#define DEFERRED   "@"
#define LITERAL	   "#"
#else
#define DEFERRED   "*"
#define LITERAL	   "$"
#endif
/*
 * disassembling vax instructions works as follows:
 *
 * 1.	get first byte as opcode (check for two-byte opcodes!)
 * 2.	lookup in op-table for mnemonic and operand-list
 * 2.a	store the mnemonic
 * 3.	for each operand in list: get the size/type
 * 3.a	evaluate addressing mode for this operand
 * 3.b	store each operand(s)
 * 4.	db_printf the opcode and the (value of the) operands
 * 5.	return the start of the next instruction
 *
 * - if jump/branch calculate (and display) the target-address
 */

/*
#define BROKEN_DB_REGS
*/
#ifdef	BROKEN_DB_REGS
struct {		/* Due to order and contents of db_regs[], we can't */
	char *name;	/* use this array to extract register-names. */
	void *valuep;	/* eg. "psl" vs "pc", "pc" vs "sp" */
} my_db_regs[16] = {
	{ "r0",		NULL },
	{ "r1",		NULL },
	{ "r2",		NULL },
	{ "r3",		NULL },
	{ "r4",		NULL },
	{ "r5",		NULL },
	{ "r6",		NULL },
	{ "r7",		NULL },
	{ "r8",		NULL },
	{ "r9",		NULL },
	{ "r10",	NULL },
	{ "r11",	NULL },
	{ "ap",		NULL },		/* aka "r12" */
	{ "fp",		NULL },		/* aka "r13" */
	{ "sp",		NULL },		/* aka "r14" */
	{ "pc",		NULL },		/* aka "r15" */
};
#else
#define my_db_regs db_regs
#endif

typedef struct {
	char		dasm[256];	/* disassembled instruction as text */
	char	       *ppc;	/* pseudo PC */
	u_int		opc;	/* op-code */
	char	       *argp;	/* pointer into argument-list */
	int		off;	/* offset specified by last argument */
	int		addr;	/* address specified by last argument */
} inst_buffer;

int get_byte(inst_buffer * ib);
int get_word(inst_buffer * ib);
int get_long(inst_buffer * ib);

int get_opcode(inst_buffer * ib);
int get_operands(inst_buffer * ib);
int get_operand(inst_buffer * ib, int size);

void add_str(inst_buffer * ib, char *s);
void add_int(inst_buffer * ib, int i);
void add_xint(inst_buffer * ib, int i);
void add_sym(inst_buffer * ib, int i);
void add_off(inst_buffer * ib, int i);

#define err_print  printf

/*
 * Disassemble instruction at 'loc'.  'altfmt' specifies an
 * (optional) alternate format (altfmt for vax: don't assume
 * that each external label is a procedure entry mask).
 * Return address of start of next instruction.
 * Since this function is used by 'examine' and by 'step'
 * "next instruction" does NOT mean the next instruction to
 * be executed but the 'linear' next instruction.
 */
db_addr_t
db_disasm(loc, altfmt)
	db_addr_t	loc;
	boolean_t	altfmt;
{
	db_expr_t	diff;
	db_sym_t	sym;
	char	       *symname;

	inst_buffer	ib;

	bzero(&ib, sizeof(ib));
	ib.ppc = (void *)loc;

	if (!altfmt) {		/* ignore potential entry masks in altfmt */
		diff = INT_MAX;
		symname = NULL;
		sym = db_search_symbol(loc, DB_STGY_PROC, &diff);
		db_symbol_values(sym, &symname, 0);

		if (symname && diff == 0) { /* symbol at loc */
			db_printf("function \"%s()\", entry-mask 0x%x\n",
				  symname, (unsigned short) get_word(&ib));
			db_printsym((db_addr_t)ib.ppc, DB_STGY_ANY, db_printf);
			db_printf(":\t");
		}
	}

	get_opcode(&ib);
	get_operands(&ib);
	db_printf("%s\n", ib.dasm);

	return ((u_int) ib.ppc);
}

int
get_opcode(ib)
	inst_buffer    *ib;
{
	ib->opc = get_byte(ib);
	if (ib->opc >= 0xfd) {
		/* two byte op-code */
		ib->opc = ib->opc << 8;
		ib->opc += get_byte(ib);
	}

	if (ib->opc > 0xffff) {
		add_str(ib, "invalid opcode ");
		add_xint(ib, ib->opc);
	} else {
		if (ib->opc > 0xff)
			add_str(ib, vax_inst2[INDEX_OPCODE(ib->opc)].mnemonic);
		else
			add_str(ib, vax_inst[ib->opc].mnemonic);
		add_str(ib, "\t");
	}
	return (ib->opc);
}

int
get_operands(ib)
	inst_buffer    *ib;
{
	int		aa = 0; /* absolute address mode ? */
	int		size;

	if (ib->opc > 0xffff) {
		/* invalid opcode */
		ib->argp = NULL;
		return (-1);
	} else if (ib->opc > 0xff) {
		/* two-byte opcode */
		ib->argp = vax_inst2[INDEX_OPCODE(ib->opc)].argdesc;
	} else
		ib->argp = vax_inst[ib->opc].argdesc;

	if (ib->argp == NULL)
		return (0);

	while (*ib->argp) {
		switch (*ib->argp) {

		case 'b':	/* branch displacement */
			switch (*(++ib->argp)) {
			case 'b':
				ib->off = (signed char) get_byte(ib);
				break;
			case 'w':
				ib->off = (short) get_word(ib);
				break;
			case 'l':
				ib->off = get_long(ib);
				break;
			default:
				err_print("invalid branch-type %X (%c) found.\n",
					  *ib->argp, *ib->argp);
			}
			/* add_int(ib, ib->off); */
			ib->addr = (u_int) ib->ppc + ib->off;
			add_off(ib, ib->addr);
			break;

		case 'a':	/* absolute addressing mode */
			aa = 1;
			/* FALLTHROUGH */

		default:
			switch (*(++ib->argp)) {
			case 'b':	/* Byte */
				size = SIZE_BYTE;
				break;
			case 'w':	/* Word */
				size = SIZE_WORD;
				break;
			case 'l':	/* Long-Word */
			case 'f':	/* F_Floating */
				size = SIZE_LONG;
				break;
			case 'q':	/* Quad-Word */
			case 'd':	/* D_Floating */
			case 'g':	/* G_Floating */
				size = SIZE_QWORD;
				break;
			case 'o':	/* Octa-Word */
			case 'h':	/* H_Floating */
				size = SIZE_OWORD;
				break;
			default:
				err_print("invalid op-type %X (%c) found.\n",
					  *ib->argp, *ib->argp);
				size = 0;
			}
			if (aa) {
				/* get the address */
				ib->addr = get_operand(ib, size);
				add_sym(ib, ib->addr);
			} else {
				/* get the operand */
				ib->addr = get_operand(ib, size);
				add_off(ib, ib->addr);
			}
		}

		if (!*ib->argp || !*++ib->argp)
			break;
		if (*ib->argp++ == ',') {
			add_str(ib, ", ");
		} else {
			err_print("error in opcodes.c\n");
			return (-1);
		}
	}

	return (0);
}

int
get_operand(ib, size)
	inst_buffer    *ib;
	int		size;
{
	int		c = get_byte(ib);
	int		mode = c >> 4;
	int		reg = c & 0x0F;
	int		lit = c & 0x3F;
	int		tmp = 0;
	char		buf[16];

	switch (mode) {
	case 0:		/* literal */
	case 1:		/* literal */
	case 2:		/* literal */
	case 3:		/* literal */
		add_str(ib, LITERAL);
		add_int(ib, lit);
		tmp = lit;
		break;

	case 4:		/* indexed */
		snprintf(buf, sizeof buf, "[%s]", my_db_regs[reg].name);
		get_operand(ib, 0);
		add_str(ib, buf);
		break;

	case 5:		/* register */
		add_str(ib, my_db_regs[reg].name);
		break;

	case 6:		/* register deferred */
		add_str(ib, "(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")");
		break;

	case 7:		/* autodecrement */
		add_str(ib, "-(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")");
		if (reg == 0x0F) {	/* pc is not allowed in this mode */
			err_print("autodecrement not allowed for PC.\n");
		}
		break;

	case 9:		/* autoincrement deferred */
		add_str(ib, DEFERRED);
		if (reg == 0x0F) {	/* pc: immediate deferred */
			/*
			 * addresses are always longwords!
			 */
			tmp = get_long(ib);
			add_off(ib, tmp);
			break;
		}
		/* FALLTHROUGH */
	case 8:		/* autoincrement */
		if (reg == 0x0F) {	/* pc: immediate ==> special syntax */
			switch (size) {
			case SIZE_BYTE:
				tmp = (signed char) get_byte(ib);
				break;
			case SIZE_WORD:
				tmp = (signed short) get_word(ib);
				break;
			case SIZE_LONG:
				tmp = get_long(ib);
				break;
			default:
				err_print("illegal op-type %d\n", size);
				tmp = -1;
			}
			if (mode == 8)
				add_str(ib, LITERAL);
			add_int(ib, tmp);
			break;
		}
		add_str(ib, "(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")+");
		break;

	case 11:	/* byte displacement deferred/ relative deferred  */
		add_str(ib, DEFERRED);
	case 10:	/* byte displacement / relative mode */
		tmp = (signed char) get_byte(ib);
		if (reg == 0x0F) {
			add_off(ib, (u_int) ib->ppc + tmp);
			break;
		}
		/* add_str (ib, "b^"); */
		add_int(ib, tmp);
		add_str(ib, "(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")");
		break;

	case 13:		/* word displacement deferred */
		add_str(ib, DEFERRED);
	case 12:		/* word displacement */
		tmp = (signed short) get_word(ib);
		if (reg == 0x0F) {
			add_off(ib, (u_int) ib->ppc + tmp);
			break;
		}
		/* add_str (ib, "w^"); */
		add_int(ib, tmp);
		add_str(ib, "(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")");
		break;

	case 15:		/* long displacement deferred */
		add_str(ib, DEFERRED);
	case 14:		/* long displacement */
		tmp = get_long(ib);
		if (reg == 0x0F) {
			add_off(ib, (u_int) ib->ppc + tmp);
			break;
		}
		/* add_str (ib, "l^"); */
		add_int(ib, tmp);
		add_str(ib, "(");
		add_str(ib, my_db_regs[reg].name);
		add_str(ib, ")");
		break;

	default:
		err_print("can\'t evaluate operand (%02X).\n", lit);
		break;
	}

	return (0);
}

int
get_byte(ib)
	inst_buffer    *ib;
{
	return ((unsigned char) *(ib->ppc++));
}

int
get_word(ib)
	inst_buffer    *ib;
{
	int		tmp;
	char	       *p = (void *) &tmp;

	*p++ = get_byte(ib);
	*p++ = get_byte(ib);
	return (tmp);
}

int
get_long(ib)
	inst_buffer    *ib;
{
	int		tmp;
	char	       *p = (void *) &tmp;

	*p++ = get_byte(ib);
	*p++ = get_byte(ib);
	*p++ = get_byte(ib);
	*p++ = get_byte(ib);
	return (tmp);
}

void
add_str(ib, s)
	inst_buffer    *ib;
	char	       *s;
{

	if (s == NULL)
		s = "-reserved-";

	strlcat(ib->dasm, s, sizeof(ib->dasm));
}

void
add_int(ib, i)
	inst_buffer    *ib;
	int		i;
{
	char		buf[32];

	if (i < 100 && i > -100)
		snprintf(buf, sizeof buf, "%d", i);
	else
		snprintf(buf, sizeof buf, "0x%x", i);
	add_str(ib, buf);
}

void
add_xint(ib, val)
	inst_buffer    *ib;
	int		val;
{
	char		buf[32];

	snprintf(buf, sizeof buf, "0x%x", val);
	add_str(ib, buf);
}

void
add_sym(ib, loc)
	inst_buffer    *ib;
	int		loc;
{
	db_expr_t	diff;
	db_sym_t	sym;
	char	       *symname;

	if (!loc)
		return;

	diff = INT_MAX;
	symname = NULL;
	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
	db_symbol_values(sym, &symname, 0);

	if (symname && !diff) {
		/* add_str(ib, "<"); */
		add_str(ib, symname);
		/* add_str(ib, ">"); */
	}
	else
		add_xint(ib, loc);
}

void
add_off(ib, loc)
	inst_buffer    *ib;
	int		loc;
{
	db_expr_t	diff;
	db_sym_t	sym;
	char	       *symname;

	if (!loc)
		return;

	diff = INT_MAX;
	symname = NULL;
	sym = db_search_symbol(loc, DB_STGY_ANY, &diff);
	db_symbol_values(sym, &symname, 0);

	if (symname) {
		/* add_str(ib, "<"); */
		add_str(ib, symname);
		if (diff) {
			add_str(ib, "+");
			add_xint(ib, diff);
		}
		/* add_str(ib, ">"); */
	}
	else
		add_xint(ib, loc);
}


code:
/*	$OpenBSD: db_disasm.h,v 1.5 2015/02/07 23:30:13 miod Exp $ */
/*	$NetBSD: db_disasm.h,v 1.1 1996/01/28 11:31:27 ragge Exp $ */
/*
 * Copyright (c) 2002, Miodrag Vallat.
 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by
 * Bertram Barth.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define SIZE_BYTE	 1		/* Byte */
#define SIZE_WORD	 2		/* Word */
#define SIZE_LONG 	 4		/* Longword */
#define SIZE_QWORD	 8		/* Quadword */
#define SIZE_OWORD	16		/* Octaword */

/*
 * The VAX instruction set has a variable length instruction format which
 * may be as short as one byte and as long as needed depending on the type
 * of instruction. [...] Each instruction consists of an opcode followed
 * by zero to six operand specifiers whose number and type depend on the
 * opcode. All operand specifiers are, themselves, of the same format --
 * i.e. an address mode plus additional information.
 *
 * [VAX Architecture Handbook, p.52:  Instruction Format]
 * two-byte instruction set from
 * [VAX Architecture Reference Manual, appendix A: Opcode Assignments]
 */

/*
 * argdesc describes each arguments by two characters denoting
 * the access-type and the data-type.
 *
 * Arguments (Access-Types):
 *	r: operand is read only
 *	w: operand is written only
 *	m: operand is modified (both R and W)
 *	b: no operand reference. Branch displacement is specified.
 *	a: calculate the address of the specified operand
 *	v: if not "Rn", same as a. If "RN," R[n+1]R[n]
 * Arguments (Data-Types):
 *	b: Byte
 *	w: Word
 *	l: Longword
 *	q: Quadword
 *	o: Octaword
 *	d: D_floating
 *	f: F_floating
 *	g: G_floating
 *	h: H_floating
 *	r: Register
 *	x: first data type specified by instruction
 *	y: second data type spcified by instructin
 *	-: no-args
 *	?: unknown (variable?)
 */

typedef struct vax_instr_t {
	char *mnemonic;
	char *argdesc;
} vax_instr_t;

/* one-byte instructions */
extern vax_instr_t vax_inst[];

/* two-byte instructions */

/*
 * reasonably simple macro to gather all the reserved two-byte opcodes
 * into only a few table entries...
 */
#define	INDEX_OPCODE(x)	\
	(((x) & 0xff00) == 0xfe00) ? 0 : \
	((x) < 0xfd30) ? 0 : \
	((x) < 0xfd80) ? (x) - 0xfd30 : \
	((x) == 0xfd98) ? 0x50 : \
	((x) == 0xfd99) ? 0x51 : \
	((x) == 0xfdf6) ? 0x52 : \
	((x) == 0xfdf7) ? 0x53 : \
	((x) == 0xfffd) ? 0x54 : \
	((x) == 0xfffe) ? 0x55 : 0

extern vax_instr_t vax_inst2[];


code:
/*	$OpenBSD: db_machdep.c,v 1.19 2014/07/13 12:11:01 jasper Exp $	*/
/*	$NetBSD: db_machdep.c,v 1.17 1999/06/20 00:58:23 ragge Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 *
 *	db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
 *
 * VAX enhancements by cmcmanis@mcmanis.com no rights reserved :-)
 *
 */

/*
 * Interface to new debugger.
 * Taken from i386 port and modified for vax.
 */
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/reboot.h>
#include <sys/systm.h> /* just for boothowto --eichin */

#include <uvm/uvm_extern.h>

#include <dev/cons.h>

#include <machine/db_machdep.h>
#include <machine/trap.h>
#include <machine/frame.h>
#include <machine/pcb.h>
#include <machine/cpu.h>
#include <machine/../vax/gencons.h>

#include <ddb/db_sym.h>
#include <ddb/db_command.h>
#include <ddb/db_output.h>
#include <ddb/db_extern.h>
#include <ddb/db_access.h>
#include <ddb/db_interface.h>
#include <ddb/db_var.h>
#include <ddb/db_variables.h>

extern	label_t	*db_recover;

void	kdbprinttrap(int, int);

int	db_active = 0;
db_regs_t	ddb_regs;	/* register state */

extern int qdpolling;
static	int splsave; /* IPL before entering debugger */

/*
 * VAX Call frame on the stack, this from
 * "Computer Programming and Architecture, The VAX-11"
 *		Henry Levy & Richard Eckhouse Jr.
 *			ISBN 0-932376-07-X
 */
typedef struct __vax_frame {
	u_int	vax_cond;				/* condition handler               */
	u_int	vax_psw:16;				/* 16 bit processor status word    */
	u_int	vax_regs:12;			/* Register save mask.             */
	u_int	vax_zero:1;				/* Always zero                     */
	u_int	vax_calls:1;			/* True if CALLS, false if CALLG   */
	u_int	vax_spa:2;				/* Stack pointer alignment         */
	u_int	*vax_ap;				/* argument pointer                */
	struct __vax_frame	*vax_fp;	/* frame pointer of previous frame */
	u_int	vax_pc;					/* program counter                 */
	u_int	vax_args[1];			/* 0 or more arguments             */
} VAX_CALLFRAME;

/*
 * DDB is called by either <ESC> - D on keyboard, via a TRACE or
 * BPT trap or from kernel, normally as a result of a panic.
 * If it is the result of a panic, set the ddb register frame to
 * contain the registers when panic was called. (easy to debug).
 */
void
kdb_trap(frame)
	struct trapframe *frame;
{
	int s;

	switch (frame->trap) {
	case T_BPTFLT:	/* breakpoint */
	case T_TRCTRAP:	/* single_step */
		break;

	/* XXX todo: should be migrated to use VAX_CALLFRAME at some point */
	case T_KDBTRAP:
		if (panicstr) {
			struct	callsframe *pf, *df;

			df = (void *)frame->fp; /* start of debug's calls */
			pf = (void *)df->ca_fp;	/* start of panic's calls */
			bcopy(&pf->ca_argno, &ddb_regs.r0, sizeof(int) * 12);
			ddb_regs.fp = pf->ca_fp;
			ddb_regs.pc = pf->ca_pc;
			ddb_regs.ap = pf->ca_ap;
			ddb_regs.sp = (unsigned)pf;
			ddb_regs.psl = frame->psl & ~0x1fffe0;
			ddb_regs.psl |= pf->ca_maskpsw & 0xffe0;
			ddb_regs.psl |= (splsave << 16);
		}
		break;

	default:
		if ((boothowto & RB_KDB) == 0)
			return;

		kdbprinttrap(frame->trap, frame->code);
		if (db_recover != 0) {
			db_error("Faulted in DDB; continuing...\n");
			/*NOTREACHED*/
		}
	}

	if (!panicstr)
		bcopy(frame, &ddb_regs, sizeof(struct trapframe));

	/* XXX Should switch to interrupt stack here, if needed. */

	s = splhigh();
	db_active++;
	cnpollc(TRUE);
	db_trap(frame->trap, frame->code);
	cnpollc(FALSE);
	db_active--;
	splx(s);

	if (!panicstr)
		bcopy(&ddb_regs, frame, sizeof(struct trapframe));
	frame->sp = mfpr(PR_USP);
}

extern char *traptypes[];
extern int no_traps;

/*
 * Print trap reason.
 */
void
kdbprinttrap(type, code)
	int type, code;
{
	db_printf("kernel: ");
	if (type >= no_traps || type < 0)
		db_printf("type %d", type);
	else
		db_printf("%s", traptypes[type]);
	db_printf(" trap, code=%x\n", code);
}

/*
 * Read bytes from kernel address space for debugger.
 */
void
db_read_bytes(addr, size, data)
	db_addr_t addr;
	size_t	size;
	char	*data;
{
	bcopy((caddr_t)addr, data, size);
}

/*
 * Write bytes to kernel address space for debugger.
 */
void
db_write_bytes(addr, size, data)
	db_addr_t addr;
	size_t	size;
	char	*data;
{
	memcpy((caddr_t)addr, data, size);
}

void
Debugger()
{
	splsave = _splset(0xe);
	mtpr(0xf, PR_SIRR); /* beg for debugger */
	splx(splsave);
}

/*
 * Machine register set.
 */
struct db_variable db_regs[] = {
	{"r0",	(long *)&ddb_regs.r0,	FCN_NULL},
	{"r1",	(long *)&ddb_regs.r1,	FCN_NULL},
	{"r2",	(long *)&ddb_regs.r2,	FCN_NULL},
	{"r3",	(long *)&ddb_regs.r3,	FCN_NULL},
	{"r4",	(long *)&ddb_regs.r4,	FCN_NULL},
	{"r5",	(long *)&ddb_regs.r5,	FCN_NULL},
	{"r6",	(long *)&ddb_regs.r6,	FCN_NULL},
	{"r7",	(long *)&ddb_regs.r7,	FCN_NULL},
	{"r8",	(long *)&ddb_regs.r8,	FCN_NULL},
	{"r9",	(long *)&ddb_regs.r9,	FCN_NULL},
	{"r10",	(long *)&ddb_regs.r10,	FCN_NULL},
	{"r11",	(long *)&ddb_regs.r11,	FCN_NULL},
	{"ap",	(long *)&ddb_regs.ap,	FCN_NULL},
	{"fp",	(long *)&ddb_regs.fp,	FCN_NULL},
	{"sp",	(long *)&ddb_regs.sp,	FCN_NULL},
	{"pc",	(long *)&ddb_regs.pc,	FCN_NULL},
	{"psl",	(long *)&ddb_regs.psl,	FCN_NULL},
};
struct db_variable *db_eregs = db_regs + nitems(db_regs);

#define IN_USERLAND(x)	(((u_int)(x) & 0x80000000) == 0)

/*
 * Dump a stack traceback. Takes two arguments:
 *	fp - CALL FRAME pointer
 *	stackbase - Lowest stack value
 */
static void
db_dump_stack(VAX_CALLFRAME *fp, u_int stackbase, int (*pr)(const char *, ...))
{
	u_int nargs, arg_base, regs;
	VAX_CALLFRAME *tmp_frame;
	db_expr_t	diff;
	db_sym_t	sym;
	char		*symname;

	(*pr)("Stack traceback : \n");
	if (IN_USERLAND(fp)) {
		(*pr)("  Process is executing in user space.\n");
		return;
	}

	while ((u_int)(fp->vax_fp) > stackbase &&
	    (u_int)(fp->vax_fp) <= (stackbase + USPACE)) {
		diff = INT_MAX;
		symname = NULL;
		sym = db_search_symbol(fp->vax_pc, DB_STGY_ANY, &diff);
		db_symbol_values(sym, &symname, 0);
		(*pr)("%s+0x%lx(", symname, diff);

		/*
		 * Figure out the arguments by using a bit of subtlety.
		 * As the argument pointer may have been used as a temporary
		 * by the callee ... recreate what it would have pointed to
		 * as follows:
		 *  The vax_regs value has a 12 bit bitmask of the registers
		 *    that were saved on the stack.
		 *	Store that in 'regs' and then for every bit that is
		 *    on (indicates the register contents are on the stack)
		 *    increment the argument base (arg_base) by one.
		 *  When that is done, args[arg_base] points to the longword
		 *    that identifies the number of arguments.
		 *	arg_base+1 - arg_base+n are the argument pointers/contents.
		 */

		/* First get the frame that called this function ... */
		tmp_frame = fp->vax_fp;

		/* Isolate the saved register bits, and count them */
		regs = tmp_frame->vax_regs;
		for (arg_base = 0; regs != 0; regs >>= 1) {
			if (regs & 1)
				arg_base++;
		}

		/* number of arguments is then pointed to by vax_args[arg_base] */
		nargs = tmp_frame->vax_args[arg_base];
		if (nargs) {
			nargs--; /* reduce by one for formatting niceties */
			arg_base++; /* skip past the actual number of arguments */
			while (nargs--)
				(*pr)("0x%x,", tmp_frame->vax_args[arg_base++]);

			/* now print out the last arg with closing brace and \n */
			(*pr)("0x%x)\n", tmp_frame->vax_args[arg_base]);
		} else
			(*pr)("void)\n");
		/* move to the next frame */
		fp = fp->vax_fp;
	}
}

/*
 * Implement the trace command which has the form:
 *
 *	trace				<-- Trace panic (same as before)
 *	trace	0x88888 	<-- Trace process whose address is 888888
 *	trace/t				<-- Trace current process (0 if no current proc)
 *	trace/t	0tnn		<-- Trace process nn (0t for decimal)
 */
void
db_stack_trace_print(addr, have_addr, count, modif, pr)
        db_expr_t       addr;		/* Address parameter */
        boolean_t       have_addr;	/* True if addr is valid */
        db_expr_t       count;		/* Optional count */
        char            *modif;		/* pointer to flag modifier 't' */
	int		(*pr)(const char *, ...);
{
	extern vaddr_t 	proc0paddr, istack;
	struct proc	*p = curproc;
	struct user	*uarea;
	int		trace_proc;
	pid_t	curpid;
	char	*s;

	/* Check to see if we're tracing a process */
	trace_proc = 0;
	s = modif;
	while (!trace_proc && *s) {
		if (*s++ == 't')
			trace_proc++;	/* why yes we are */
	}

	/* Trace a panic */
	if (! trace_proc) {
		if (have_addr == 0)
			db_dump_stack((VAX_CALLFRAME *)ddb_regs.fp,
			    ddb_regs.ap, pr);
		else
			db_dump_stack((VAX_CALLFRAME *)addr, istack, pr);
		return;
	}

	/*
	 * If user typed an address its either a PID, or a Frame
	 * if no address then either current proc or panic
	 */
	if (have_addr) {
		p = pfind((int)addr);
		/* Try to be helpful by looking at it as if it were decimal */
		if (p == NULL) {
			u_int	tpid = 0;
			u_int	foo = addr;

			while (foo != 0) {
				int digit = (foo >> 28) & 0xf;
				if (digit > 9) {
					(*pr)("  No such process.\n");
					return;
				}
				tpid = tpid * 10 + digit;
				foo = foo << 4;
			}
			p = pfind(tpid);
			if (p == NULL) {
				(*pr)("  No such process.\n");
				return;
			}
		}
	} else {
		p = curproc;
		if (p == NULL) {
			(*pr)("trace: no current process! (ignored)\n");
			return;
		}
	}
	if (p == NULL) {
		uarea = (struct user *)proc0paddr;
		curpid = 0;
	} else {
		uarea = p->p_addr;
		curpid = p->p_pid;
	}
	(*pr)("Process %d\n", curpid);
	(*pr)("  PCB contents:\n");
	(*pr)("	KSP = 0x%x\n", (unsigned int)(uarea->u_pcb.KSP));
	(*pr)("	ESP = 0x%x\n", (unsigned int)(uarea->u_pcb.ESP));
	(*pr)("	SSP = 0x%x\n", (unsigned int)(uarea->u_pcb.SSP));
	(*pr)("	USP = 0x%x\n", (unsigned int)(uarea->u_pcb.USP));
	(*pr)("	R[00] = 0x%08x    R[06] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[0]), (unsigned int)(uarea->u_pcb.R[6]));
	(*pr)("	R[01] = 0x%08x    R[07] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[1]), (unsigned int)(uarea->u_pcb.R[7]));
	(*pr)("	R[02] = 0x%08x    R[08] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[2]), (unsigned int)(uarea->u_pcb.R[8]));
	(*pr)("	R[03] = 0x%08x    R[09] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[3]), (unsigned int)(uarea->u_pcb.R[9]));
	(*pr)("	R[04] = 0x%08x    R[10] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[4]), (unsigned int)(uarea->u_pcb.R[10]));
	(*pr)("	R[05] = 0x%08x    R[11] = 0x%08x\n",
		(unsigned int)(uarea->u_pcb.R[5]), (unsigned int)(uarea->u_pcb.R[11]));
	(*pr)("	AP = 0x%x\n", (unsigned int)(uarea->u_pcb.AP));
	(*pr)("	FP = 0x%x\n", (unsigned int)(uarea->u_pcb.FP));
	(*pr)("	PC = 0x%x\n", (unsigned int)(uarea->u_pcb.PC));
	(*pr)("	PSL = 0x%x\n", (unsigned int)(uarea->u_pcb.PSL));
	(*pr)("	Trap frame pointer: 0x%x\n",
							(unsigned int)(uarea->u_pcb.framep));
	db_dump_stack((VAX_CALLFRAME *)(uarea->u_pcb.FP),
	    (u_int)uarea->u_pcb.KSP, pr);
}

static int ddbescape = 0;

int
kdbrint(tkn)
	int tkn;
{

	if (ddbescape && ((tkn & 0x7f) == 'D')) {
		if (db_console)
			mtpr(0xf, PR_SIRR);
		ddbescape = 0;
		return 1;
	}

	if ((ddbescape == 0) && ((tkn & 0x7f) == 27)) {
		ddbescape = 1;
		return 1;
	}

	if (ddbescape) {
		ddbescape = 0;
		return 2;
	}

	ddbescape = 0;
	return 0;
}


code:
/*	$OpenBSD: disksubr.c,v 1.66 2011/07/06 18:32:59 miod Exp $	*/
/*	$NetBSD: disksubr.c,v 1.21 1999/06/30 18:48:06 ragge Exp $	*/

/*
 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/syslog.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/disk.h>

#include <uvm/uvm_extern.h>

#include <machine/macros.h>
#include <machine/pte.h>
#include <machine/pcb.h>
#include <machine/cpu.h>

#include <vax/mscp/mscp.h> /* For disk encoding scheme */

/*
 * Attempt to read a disk label from a device
 * using the indicated strategy routine.
 * The label must be partly set up before this:
 * secpercyl and anything required in the strategy routine
 * (e.g., sector size) must be filled in before calling us.
 */
int
readdisklabel(dev_t dev, void (*strat)(struct buf *),
    struct disklabel *lp, int spoofonly)
{
	struct buf *bp = NULL;
	char error;

	if ((error = initdisklabel(lp)))
		goto done;

	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	DL_SETBSTART(lp, 16);

	if (spoofonly)
		goto done;

	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if (biowait(bp)) {
		error = bp->b_error;
		goto done;
	}

	error = checkdisklabel(bp->b_data + LABELOFFSET, lp,
	    16, DL_GETDSIZE(lp));
	if (error == 0)
		goto done;

#if defined(CD9660)
	error = iso_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif
#if defined(UDF)
	error = udf_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/*
 * Write disk label back to device after modification.
 * Always allow writing of disk label; even if the disk is unlabeled.
 */
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
{
	struct buf *bp = NULL;
	struct disklabel *dlp;
	int error = 0;

	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	/* Read it in, slap the new label in, and write it back out */
	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if ((error = biowait(bp)) != 0)
		goto done;

	dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
	*dlp = *lp;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
	(*strat)(bp);
	error = biowait(bp);

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/*
 * Print out the name of the device; ex. TK50, RA80. DEC uses a common
 * disk type encoding scheme for most of its disks.
 */
void
disk_printtype(int unit, int type)
{
	printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type),
	    (int)MSCP_MID_CHAR(1, type));
	if (MSCP_MID_ECH(0, type))
		printf("%c", (int)MSCP_MID_CHAR(0, type));
	printf("%d\n", MSCP_MID_NUM(type));
}