code:
/*	$OpenBSD: db_interface.c,v 1.5 2014/12/03 20:09:32 krw Exp $	*/
/*	$NetBSD: db_interface.c,v 1.37 2006/09/06 00:11:49 uwe Exp $	*/

/*-
 * Copyright (C) 2002 UCHIYAMA Yasushi.  All rights reserved.
 * Copyright (c) 2000 Tsubai Masanari.  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. 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/systm.h>
#include <sys/proc.h>
#include <sys/user.h>

#include <uvm/uvm_extern.h>

#include <dev/cons.h>

#include <machine/db_machdep.h>
#include <ddb/db_run.h>
#include <ddb/db_sym.h>

#include <sh/ubcreg.h>

db_regs_t ddb_regs;		/* register state */

#include <sh/cache.h>
#include <sh/cache_sh3.h>
#include <sh/cache_sh4.h>
#include <sh/mmu.h>
#include <sh/mmu_sh3.h>
#include <sh/mmu_sh4.h>

#include <ddb/db_command.h>
#include <ddb/db_extern.h>
#include <ddb/db_output.h>
#include <ddb/db_var.h>

void kdb_printtrap(u_int, int);

void db_tlbdump_cmd(db_expr_t, int, db_expr_t, char *);
void __db_tlbdump_page_size_sh4(uint32_t);
void __db_tlbdump_pfn(uint32_t);
void db_cachedump_cmd(db_expr_t, int, db_expr_t, char *);

void __db_cachedump_sh3(vaddr_t);
void __db_cachedump_sh4(vaddr_t);

void db_stackcheck_cmd(db_expr_t, int, db_expr_t, char *);
void db_frame_cmd(db_expr_t, int, db_expr_t, char *);
void __db_print_symbol(db_expr_t);
char *__db_procname_by_asid(int);

struct db_command db_machine_command_table[] = {
	{ "tlb",	db_tlbdump_cmd,		0,	NULL },
	{ "cache",	db_cachedump_cmd,	0,	NULL },
	{ "frame",	db_frame_cmd,		0,	NULL },
#ifdef KSTACK_DEBUG
	{ "stack",	db_stackcheck_cmd,	0,	NULL },
#endif
	{ NULL }
};

int db_active;

void
db_machine_init(void)
{

	db_machine_commands_install(db_machine_command_table);
}

void
kdb_printtrap(u_int type, int code)
{
	int i;
	i = type >> 5;

	db_printf("%s mode trap: ", type & 1 ? "user" : "kernel");
	if (i >= exp_types)
		db_printf("type 0x%03x", type & ~1);
	else
		db_printf("%s", exp_type[i]);

	db_printf(" code = 0x%x\n", code);
}

int
kdb_trap(int type, int code, db_regs_t *regs)
{
	extern label_t *db_recover;
	int s;

	switch (type) {
	case EXPEVT_TRAPA:	/* trapa instruction */
	case EXPEVT_BREAK:	/* UBC */
	case -1:		/* keyboard interrupt */
		break;
	default:
		if (!db_panic && db_recover == NULL)
			return 0;

		kdb_printtrap(type, code);
		if (db_recover != NULL) {
			db_error("Faulted in DDB; continuing...\n");
			/*NOTREACHED*/
		}
	}

	/* XXX Should switch to kdb's own stack here. */

	ddb_regs = *regs;

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

	*regs = ddb_regs;

	return 1;
}

void
Debugger()
{
	__asm volatile("trapa %0" :: "i"(_SH_TRA_BREAK));
}

#define	M_BSR	0xf000
#define	I_BSR	0xb000
#define	M_BSRF	0xf0ff
#define	I_BSRF	0x0003
#define	M_JSR	0xf0ff
#define	I_JSR	0x400b
#define	M_RTS	0xffff
#define	I_RTS	0x000b
#define	M_RTE	0xffff
#define	I_RTE	0x002b

boolean_t
inst_call(int inst)
{
#if _BYTE_ORDER == BIG_ENDIAN
	inst >>= 16;
#endif
	return (inst & M_BSR) == I_BSR || (inst & M_BSRF) == I_BSRF ||
	       (inst & M_JSR) == I_JSR;
}

boolean_t
inst_return(int inst)
{
#if _BYTE_ORDER == BIG_ENDIAN
	inst >>= 16;
#endif
	return (inst & M_RTS) == I_RTS;
}

boolean_t
inst_trap_return(int inst)
{
#if _BYTE_ORDER == BIG_ENDIAN
	inst >>= 16;
#endif
	return (inst & M_RTE) == I_RTE;
}

void
db_set_single_step(db_regs_t *regs)
{

	_reg_write_2(SH_(BBRA), 0);		/* disable break */
	_reg_write_4(SH_(BARA), 0);		/* break address */
	_reg_write_1(SH_(BASRA), 0);		/* break ASID */
	_reg_write_1(SH_(BAMRA), 0x07);		/* break always */
	_reg_write_2(SH_(BRCR),  0x400);	/* break after each execution */

	regs->tf_ubc = 0x0014;	/* will be written to BBRA */
}

void
db_clear_single_step(db_regs_t *regs)
{

	regs->tf_ubc = 0;
}

#define	ON(x, c)	((x) & (c) ? '|' : '.')

/*
 * MMU
 */
void
db_tlbdump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
    char *modif)
{
	static const char *pr[] = { "_r", "_w", "rr", "ww" };
	static const char title[] =
	    "   VPN      ASID    PFN  AREA VDCGWtPR  SZ";
	static const char title2[] =
	    "          U/K                       U/K";
	uint32_t r, e;
	int i;
#ifdef SH3
	if (CPU_IS_SH3) {
		/* MMU configuration. */
		r = _reg_read_4(SH3_MMUCR);
		db_printf("%s-mode, %s virtual storage mode\n",
		    r & SH3_MMUCR_IX
		    ? "ASID + VPN" : "VPN only",
		    r & SH3_MMUCR_SV ? "single" : "multiple");
		i = _reg_read_4(SH3_PTEH) & SH3_PTEH_ASID_MASK;
		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));

		db_printf("---TLB DUMP---\n%s\n%s\n", title, title2);
		for (i = 0; i < SH3_MMU_WAY; i++) {
			db_printf(" [way %d]\n", i);
			for (e = 0; e < SH3_MMU_ENTRY; e++) {
				uint32_t a;
				/* address/data array common offset. */
				a = (e << SH3_MMU_VPN_SHIFT) |
				    (i << SH3_MMU_WAY_SHIFT);

				r = _reg_read_4(SH3_MMUAA | a);
				if (r == 0) {
					db_printf("---------- - --- ----------"
					    " - ----x --  --\n");
				} else {
					vaddr_t va;
					int asid;
					asid = r & SH3_MMUAA_D_ASID_MASK;
					r &= SH3_MMUAA_D_VPN_MASK_1K;
					va = r | (e << SH3_MMU_VPN_SHIFT);
					db_printf("0x%08lx %c %3d", va,
					    (int)va < 0 ? 'K' : 'U', asid);

					r = _reg_read_4(SH3_MMUDA | a);
					__db_tlbdump_pfn(r);

					db_printf(" %c%c%c%cx %s %2dK\n",
					    ON(r, SH3_MMUDA_D_V),
					    ON(r, SH3_MMUDA_D_D),
					    ON(r, SH3_MMUDA_D_C),
					    ON(r, SH3_MMUDA_D_SH),
					    pr[(r & SH3_MMUDA_D_PR_MASK) >>
						SH3_MMUDA_D_PR_SHIFT],
					    r & SH3_MMUDA_D_SZ ? 4 : 1);
				}
			}
		}
	}
#endif /* SH3 */
#ifdef SH4
	if (CPU_IS_SH4) {
		/* MMU configuration */
		r = _reg_read_4(SH4_MMUCR);
		db_printf("%s virtual storage mode, SQ access: (kernel%s)\n",
		    r & SH3_MMUCR_SV ? "single" : "multiple",
		    r & SH4_MMUCR_SQMD ? "" : "/user");
		db_printf("random counter limit=%d\n",
		    (r & SH4_MMUCR_URB_MASK) >> SH4_MMUCR_URB_SHIFT);

		i = _reg_read_4(SH4_PTEH) & SH4_PTEH_ASID_MASK;
		db_printf("ASID=%d (%s)", i, __db_procname_by_asid(i));

		/* Dump ITLB */
		db_printf("---ITLB DUMP ---\n%s TC SA\n%s\n", title, title2);
		for (i = 0; i < 4; i++) {
			e = i << SH4_ITLB_E_SHIFT;

			r = _reg_read_4(SH4_ITLB_AA | e);
			db_printf("0x%08x   %3d",
			    r & SH4_ITLB_AA_VPN_MASK,
			    r & SH4_ITLB_AA_ASID_MASK);

			r = _reg_read_4(SH4_ITLB_DA1 | e);
			__db_tlbdump_pfn(r);
			db_printf(" %c_%c%c_ %s ",
			    ON(r, SH4_ITLB_DA1_V),
			    ON(r, SH4_ITLB_DA1_C),
			    ON(r, SH4_ITLB_DA1_SH),
			    pr[(r & SH4_ITLB_DA1_PR) >>
				SH4_UTLB_DA1_PR_SHIFT]);
			__db_tlbdump_page_size_sh4(r);

#if 0 /* XXX: causes weird effects on landisk */
			r = _reg_read_4(SH4_ITLB_DA2 | e);
			db_printf(" %c  %d\n",
			    ON(r, SH4_ITLB_DA2_TC),
			    r & SH4_ITLB_DA2_SA_MASK);
#else
			db_printf("\n");
#endif
		}

		/* Dump UTLB */
		db_printf("---UTLB DUMP---\n%s TC SA\n%s\n", title, title2);
		for (i = 0; i < 64; i++) {
			e = i << SH4_UTLB_E_SHIFT;

			r = _reg_read_4(SH4_UTLB_AA | e);
			db_printf("0x%08x   %3d",
			    r & SH4_UTLB_AA_VPN_MASK,
			    r & SH4_UTLB_AA_ASID_MASK);

			r = _reg_read_4(SH4_UTLB_DA1 | e);
			__db_tlbdump_pfn(r);
			db_printf(" %c%c%c%c%c %s ",
			    ON(r, SH4_UTLB_DA1_V),
			    ON(r, SH4_UTLB_DA1_D),
			    ON(r, SH4_UTLB_DA1_C),
			    ON(r, SH4_UTLB_DA1_SH),
			    ON(r, SH4_UTLB_DA1_WT),
			    pr[(r & SH4_UTLB_DA1_PR_MASK) >>
				SH4_UTLB_DA1_PR_SHIFT]
			    );
			__db_tlbdump_page_size_sh4(r);

#if 0 /* XXX: causes weird effects on landisk */
			r = _reg_read_4(SH4_UTLB_DA2 | e);
			db_printf(" %c  %d\n",
			    ON(r, SH4_UTLB_DA2_TC),
			    r & SH4_UTLB_DA2_SA_MASK);
#else
			db_printf("\n");
#endif
		}
	}
#endif /* SH4 */
}

void
__db_tlbdump_pfn(uint32_t r)
{
	uint32_t pa = (r & SH3_MMUDA_D_PPN_MASK);

	db_printf(" 0x%08x %d", pa, (pa >> 26) & 7);
}

char *
__db_procname_by_asid(int asid)
{
	static char notfound[] = "---";
	struct process *pr;
	struct proc *p;

	LIST_FOREACH(pr, &allprocess, ps_list) {
		/* find a thread that still has the process vmspace attached */
		TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link)
			if (p->p_vmspace != NULL)
				break;
		if (p != NULL && p->p_vmspace->vm_map.pmap->pm_asid == asid)
			return (p->p_comm);
	}

	return (notfound);
}

#ifdef SH4
void
__db_tlbdump_page_size_sh4(uint32_t r)
{
	switch (r & SH4_PTEL_SZ_MASK) {
	case SH4_PTEL_SZ_1K:
		db_printf(" 1K");
		break;
	case SH4_PTEL_SZ_4K:
		db_printf(" 4K");
		break;
	case SH4_PTEL_SZ_64K:
		db_printf("64K");
		break;
	case SH4_PTEL_SZ_1M:
		db_printf(" 1M");
		break;
	}
}
#endif /* SH4 */

/*
 * CACHE
 */
void
db_cachedump_cmd(db_expr_t addr, int have_addr, db_expr_t count,
    char *modif)
{
#ifdef SH3
	if (CPU_IS_SH3)
		__db_cachedump_sh3(have_addr ? addr : 0);
#endif
#ifdef SH4
	if (CPU_IS_SH4)
		__db_cachedump_sh4(have_addr ? addr : 0);
#endif
}

#ifdef SH3
void
__db_cachedump_sh3(vaddr_t va_start)
{
	uint32_t r;
	vaddr_t va, va_end, cca;
	int entry, way;

	RUN_P2;
	/* disable cache */
	_reg_write_4(SH3_CCR,
	    _reg_read_4(SH3_CCR) & ~SH3_CCR_CE);

	if (va_start) {
		va = va_start & ~(sh_cache_line_size - 1);
		va_end = va + sh_cache_line_size;
	} else {
		va = 0;
		va_end = sh_cache_way_size;
	}

	db_printf("%d-way, way-size=%dB, way-shift=%d, entry-mask=%08x, "
	    "line-size=%dB \n", sh_cache_ways, sh_cache_way_size,
	    sh_cache_way_shift, sh_cache_entry_mask, sh_cache_line_size);
	db_printf("Entry  Way 0  UV   Way 1  UV   Way 2  UV   Way 3  UV\n");
	for (; va < va_end; va += sh_cache_line_size) {
		entry = va & sh_cache_entry_mask;
		cca = SH3_CCA | entry;
		db_printf(" %3d ", entry >> CCA_ENTRY_SHIFT);
		for (way = 0; way < sh_cache_ways; way++) {
			r = _reg_read_4(cca | (way << sh_cache_way_shift));
			db_printf("%08x %c%c ", r & CCA_TAGADDR_MASK,
			    ON(r, CCA_U), ON(r, CCA_V));
		}
		db_printf("\n");
	}

	/* enable cache */
	_reg_bset_4(SH3_CCR, SH3_CCR_CE);
	sh_icache_sync_all();

	RUN_P1;
}
#endif /* SH3 */

#ifdef SH4
void
__db_cachedump_sh4(vaddr_t va)
{
	uint32_t r, e;
	int i, istart, iend;

	RUN_P2; /* must access from P2 */

	/* disable I/D-cache */
	_reg_write_4(SH4_CCR,
	    _reg_read_4(SH4_CCR) & ~(SH4_CCR_ICE | SH4_CCR_OCE));

	if (va) {
		istart = ((va & CCIA_ENTRY_MASK) >> CCIA_ENTRY_SHIFT) & ~3;
		iend = istart + 4;
	} else {
		istart = 0;
		iend = SH4_ICACHE_SIZE / SH4_CACHE_LINESZ;
	}

	db_printf("[I-cache]\n");
	db_printf("  Entry             V           V           V           V\n");
	for (i = istart; i < iend; i++) {
		if ((i & 3) == 0)
			db_printf("\n[%3d-%3d] ", i, i + 3);
		r = _reg_read_4(SH4_CCIA | (i << CCIA_ENTRY_SHIFT));
		db_printf("%08x _%c ", r & CCIA_TAGADDR_MASK, ON(r, CCIA_V));
	}

	db_printf("\n[D-cache]\n");
	db_printf("  Entry            UV          UV          UV          UV\n");
	for (i = istart; i < iend; i++) {
		if ((i & 3) == 0)
			db_printf("\n[%3d-%3d] ", i, i + 3);
		e = (i << CCDA_ENTRY_SHIFT);
		r = _reg_read_4(SH4_CCDA | e);
		db_printf("%08x %c%c ", r & CCDA_TAGADDR_MASK, ON(r, CCDA_U),
		    ON(r, CCDA_V));

	}
	db_printf("\n");

	_reg_write_4(SH4_CCR,
	    _reg_read_4(SH4_CCR) | SH4_CCR_ICE | SH4_CCR_OCE);
	sh_icache_sync_all();

	RUN_P1;
}
#endif /* SH4 */

#undef ON

void
db_frame_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	struct switchframe *sf = &curpcb->pcb_sf;
	struct trapframe *tf, *tftop;

	/* Print switch frame */
	db_printf("[switch frame]\n");

#define	SF(x)	db_printf("sf_" #x "\t\t0x%08x\t", sf->sf_ ## x);	\
		__db_print_symbol(sf->sf_ ## x)

	SF(sr);
	SF(r15);
	SF(r14);
	SF(r13);
	SF(r12);
	SF(r11);
	SF(r10);
	SF(r9);
	SF(r8);
	SF(pr);
	db_printf("sf_r6_bank\t0x%08x\n", sf->sf_r6_bank);
	db_printf("sf_r7_bank\t0x%08x\n", sf->sf_r7_bank);

	/* Print trap frame stack */
	db_printf("[trap frame]\n");

	__asm("stc r6_bank, %0" : "=r"(tf));
	tftop = (struct trapframe *)((vaddr_t)curpcb + PAGE_SIZE);

	for (; tf != tftop; tf++) {
		db_printf("-- %p-%p --\n", tf, tf + 1);
		db_printf("tf_expevt\t0x%08x\n", tf->tf_expevt);

#define	TF(x)	db_printf("tf_" #x "\t\t0x%08x\t", tf->tf_ ## x);	\
		__db_print_symbol(tf->tf_ ## x)

		TF(ubc);
		TF(spc);
		TF(ssr);
		TF(macl);
		TF(mach);
		TF(pr);
		TF(r13);
		TF(r12);
		TF(r11);
		TF(r10);
		TF(r9);
		TF(r8);
		TF(r7);
		TF(r6);
		TF(r5);
		TF(r4);
		TF(r3);
		TF(r2);
		TF(r1);
		TF(r0);
		TF(r15);
		TF(r14);
	}
#undef	SF
#undef	TF
}

void
__db_print_symbol(db_expr_t value)
{
	char *name;
	db_expr_t offset;

	db_find_sym_and_offset((db_addr_t)value, &name, &offset);
	if (name != NULL && offset <= db_maxoff && offset != value)
		db_printsym(value, DB_STGY_ANY, db_printf);

	db_printf("\n");
}

#ifdef KSTACK_DEBUG
/*
 * Stack overflow check
 */
void
db_stackcheck_cmd(db_expr_t addr, int have_addr, db_expr_t count,
		  char *modif)
{
	struct proc *p;
	struct user *u;
	struct pcb *pcb;
	uint32_t *t32;
	uint8_t *t8;
	int i, j;

#define	MAX_STACK	(USPACE - PAGE_SIZE)
#define	MAX_FRAME	(PAGE_SIZE - sizeof(struct user))

	db_printf("stack max: %d byte, frame max %d byte,"
	    " sizeof(struct trapframe) %d byte\n", MAX_STACK, MAX_FRAME,
	    sizeof(struct trapframe));
	db_printf("   PID.LID    "
		  "stack top    max used    frame top     max used"
		  "  nest\n");

	LIST_FOREACH(p, &allproc, p_list) {
		u = p->p_addr;
		pcb = &u->u_pcb;
		/* stack */
		t32 = (uint32_t *)(pcb->pcb_sf.sf_r7_bank - MAX_STACK);
		for (i = 0; *t32++ == 0xa5a5a5a5; i++)
			continue;
		i = MAX_STACK - i * sizeof(int);

		/* frame */
		t8 = (uint8_t *)((vaddr_t)pcb + PAGE_SIZE - MAX_FRAME);
		for (j = 0; *t8++ == 0x5a; j++)
			continue;
		j = MAX_FRAME - j;

		db_printf("%6d 0x%08x %6d (%3d%%) 0x%08lx %6d (%3d%%) %d %s\n",
		    p->p_lid,
		    pcb->pcb_sf.sf_r7_bank, i, i * 100 / MAX_STACK,
		    (vaddr_t)pcb + PAGE_SIZE, j, j * 100 / MAX_FRAME,
		    j / sizeof(struct trapframe),
		    p->p_comm);
	}
#undef	MAX_STACK
#undef	MAX_FRAME
}
#endif /* KSTACK_DEBUG */


code:
/*	$OpenBSD: db_memrw.c,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $	*/
/*	$NetBSD: db_memrw.c,v 1.8 2006/02/24 00:57:19 uwe 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
 * 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)
 */

/*
 * Routines to read and write memory on behalf of the debugger, used
 * by DDB.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/db_machdep.h>

#include <ddb/db_access.h>

/*
 * Read bytes from kernel address space for debugger.
 */
void
db_read_bytes(vaddr_t addr, size_t size, char *data)
{
	char *src = (char *)addr;

	/* properly aligned 4-byte */
	if (size == 4 && ((addr & 3) == 0) && (((uintptr_t)data & 3) == 0)) {
		*(uint32_t *)data = *(uint32_t *)src;
		return;
	}

	/* properly aligned 2-byte */
	if (size == 2 && ((addr & 1) == 0) && (((uintptr_t)data & 1) == 0)) {
		*(uint16_t *)data = *(uint16_t *)src;
		return;
	}

	while (size-- > 0)
		*data++ = *src++;
}

/*
 * Write bytes to kernel address space for debugger.
 */
void
db_write_bytes(vaddr_t addr, size_t size, char *data)
{
	char *dst = (char *)addr;

	/* properly aligned 4-byte */
	if (size == 4 && ((addr & 3) == 0) && (((uintptr_t)data & 3) == 0)) {
		*(uint32_t *)dst = *(const uint32_t *)data;
		return;
	}

	/* properly aligned 2-byte */
	if (size == 2 && ((addr & 1) == 0) && (((uintptr_t)data & 1) == 0)) {
		*(uint16_t *)dst = *(const uint16_t *)data;
		return;
	}

	while (size-- > 0)
		*dst++ = *data++;
}

license: unknown


code:
/*	$OpenBSD: db_trace.c,v 1.6 2014/07/13 12:11:01 jasper Exp $	*/
/*	$NetBSD: db_trace.c,v 1.19 2006/01/21 22:10:59 uwe Exp $	*/

/*-
 * Copyright (c) 2000 Tsubai Masanari.  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. 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/systm.h>

#include <machine/db_machdep.h>

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

#ifdef TRACE_DEBUG
# define DPRINTF printf
#else
# define DPRINTF while (/* CONSTCOND */ 0) printf
#endif

extern char start[], etext[];
void db_nextframe(db_addr_t, db_addr_t *, db_addr_t *);

struct db_variable db_regs[] = {
	{ "r0",   (long *)&ddb_regs.tf_r0,   FCN_NULL },
	{ "r1",   (long *)&ddb_regs.tf_r1,   FCN_NULL },
	{ "r2",   (long *)&ddb_regs.tf_r2,   FCN_NULL },
	{ "r3",   (long *)&ddb_regs.tf_r3,   FCN_NULL },
	{ "r4",   (long *)&ddb_regs.tf_r4,   FCN_NULL },
	{ "r5",   (long *)&ddb_regs.tf_r5,   FCN_NULL },
	{ "r6",   (long *)&ddb_regs.tf_r6,   FCN_NULL },
	{ "r7",   (long *)&ddb_regs.tf_r7,   FCN_NULL },
	{ "r8",   (long *)&ddb_regs.tf_r8,   FCN_NULL },
	{ "r9",   (long *)&ddb_regs.tf_r9,   FCN_NULL },
	{ "r10",  (long *)&ddb_regs.tf_r10,  FCN_NULL },
	{ "r11",  (long *)&ddb_regs.tf_r11,  FCN_NULL },
	{ "r12",  (long *)&ddb_regs.tf_r12,  FCN_NULL },
	{ "r13",  (long *)&ddb_regs.tf_r13,  FCN_NULL },
	{ "r14",  (long *)&ddb_regs.tf_r14,  FCN_NULL },
	{ "r15",  (long *)&ddb_regs.tf_r15,  FCN_NULL },
	{ "pr",   (long *)&ddb_regs.tf_pr,   FCN_NULL },
	{ "spc",  (long *)&ddb_regs.tf_spc,  FCN_NULL },
	{ "ssr",  (long *)&ddb_regs.tf_ssr,  FCN_NULL },
	{ "mach", (long *)&ddb_regs.tf_mach, FCN_NULL },
	{ "macl", (long *)&ddb_regs.tf_macl, FCN_NULL },
};

struct db_variable *db_eregs = db_regs + nitems(db_regs);

void
db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
    char *modif, int (*print)(const char *, ...))
{
	db_addr_t callpc, frame, lastframe;
	uint32_t vbr;

	if (have_addr) {
		(*print)("sh trace requires a trap frame... giving up\n");
		return;
	}

	__asm volatile("stc vbr, %0" : "=r"(vbr));

	frame = ddb_regs.tf_r14;
	callpc = ddb_regs.tf_spc;

	if (count == 0 || count == -1)
		count = INT_MAX;

	lastframe = 0;
	while (count > 0 && frame != 0) {
		/* Are we crossing a trap frame? */
		if ((callpc & ~PAGE_MASK) == vbr) {
			struct trapframe *tf = (void *)frame;

			frame = tf->tf_r14;
			callpc = tf->tf_spc;

			(*print)("(EXPEVT %03x; SSR=%08x) at ",
				 tf->tf_expevt, tf->tf_ssr);
			db_printsym(callpc, DB_STGY_PROC, print);
			(*print)("\n");

			/* XXX: don't venture into the userland yet */
			if ((tf->tf_ssr & PSL_MD) == 0)
				break;
		} else {
			char *name;
			db_expr_t offset;
			db_sym_t sym;

			DPRINTF("    (1)newpc 0x%lx, newfp 0x%lx\n",
				callpc, frame);

			sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
			db_symbol_values(sym, &name, NULL);

			(*print)("%s() at ", name ? name : "");
			db_printsym(callpc, DB_STGY_PROC, print);
			(*print)("\n");

			if (lastframe == 0 && offset == 0) {
				callpc = ddb_regs.tf_pr;
				continue;
			}

			db_nextframe(callpc - offset, &frame, &callpc);
			DPRINTF("    (2)newpc 0x%lx, newfp 0x%lx\n",
				callpc, frame);

			if (callpc == 0 && lastframe == 0)
				callpc = (db_addr_t)ddb_regs.tf_pr;
			DPRINTF("    (3)newpc 0x%lx, newfp 0x%lx\n",
				callpc, frame);
		}

		count--;
		lastframe = frame;
	}
}

void
db_nextframe(
	db_addr_t pc,		/* in: entry address of current function */
	db_addr_t *fp,		/* in: current fp, out: parent fp */
	db_addr_t *pr)		/* out: parent pr */
{
	int *frame = (void *)*fp;
	int i, inst;
	int depth, prdepth, fpdepth;

	depth = 0;
	prdepth = fpdepth = -1;

	if (pc < (db_addr_t)start || pc > (db_addr_t)etext)
		goto out;

	for (i = 0; i < 30; i++) {
		inst = db_get_value(pc, 2, FALSE);
		pc += 2;

		if (inst == 0x6ef3)	/* mov r15,r14 -- end of prologue */
			break;

		if (inst == 0x4f22) {			/* sts.l pr,@-r15 */
			prdepth = depth;
			depth++;
			continue;
		}
		if (inst == 0x2fe6) {			/* mov.l r14,@-r15 */
			fpdepth = depth;
			depth++;
			continue;
		}
		if ((inst & 0xff0f) == 0x2f06) {	/* mov.l r?,@-r15 */
			depth++;
			continue;
		}
		if ((inst & 0xff00) == 0x7f00) {	/* add #n,r15 */
			int8_t n = inst & 0xff;

			if (n >= 0) {
				printf("add #n,r15  (n > 0)\n");
				break;
			}

			depth += -n/4;
			continue;
		}
		if ((inst & 0xf000) == 0x9000) {
			if (db_get_value(pc, 2, FALSE) == 0x3f38) {
				/* "mov #n,r3; sub r3,r15" */
				unsigned int disp = (int)(inst & 0xff);
				int r3;

				r3 = db_get_value(pc + 4 - 2 + (disp << 1),
				    2, FALSE);
				if ((r3 & 0x00008000) == 0)
					r3 &= 0x0000ffff;
				else
					r3 |= 0xffff0000;
				depth += (r3 / 4);

				pc += 2;
				continue;
			}
		}

#ifdef TRACE_DEBUG
		printf("unknown instruction in prologue\n");
		db_disasm(pc - 2, 0);
#endif
	}

 out:
#ifdef TRACE_DEBUG
	printf("depth=%x fpdepth=0x%x prdepth=0x%x\n", depth, fpdepth, prdepth);
#endif
	if (fpdepth != -1)
		*fp = frame[depth - fpdepth - 1];
	else
		*fp = 0;

	if (prdepth != -1)
		*pr = frame[depth - prdepth - 1];
	else
		*pr = 0;
}


code:
/*	$OpenBSD: devreg.c,v 1.2 2008/06/26 05:42:13 ray Exp $	*/
/*	$NetBSD: devreg.c,v 1.6 2006/03/04 01:13:35 uwe Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * 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.
 *
 * 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.
 */

#include <sys/param.h>

#include <sh/cache_sh3.h>
#include <sh/cache_sh4.h>
#include <sh/mmu_sh3.h>
#include <sh/mmu_sh4.h>
#include <sh/trap.h>

#include <sh/ubcreg.h>
#include <sh/rtcreg.h>
#include <sh/tmureg.h>

/* MMU */
uint32_t __sh_PTEH;
uint32_t __sh_TTB;
uint32_t __sh_TEA;
uint32_t __sh_TRA;
uint32_t __sh_EXPEVT;
uint32_t __sh_INTEVT;

/* UBC */
uint32_t __sh_BARA;
uint32_t __sh_BAMRA;
uint32_t __sh_BASRA;
uint32_t __sh_BBRA;
uint32_t __sh_BARB;
uint32_t __sh_BAMRB;
uint32_t __sh_BASRB;
uint32_t __sh_BBRB;
uint32_t __sh_BDRB;
uint32_t __sh_BDMRB;
uint32_t __sh_BRCR;

/* RTC */
uint32_t __sh_R64CNT;
uint32_t __sh_RSECCNT;
uint32_t __sh_RMINCNT;
uint32_t __sh_RHRCNT;
uint32_t __sh_RWKCNT;
uint32_t __sh_RDAYCNT;
uint32_t __sh_RMONCNT;
uint32_t __sh_RYRCNT;
uint32_t __sh_RSECAR;
uint32_t __sh_RMINAR;
uint32_t __sh_RHRAR;
uint32_t __sh_RWKAR;
uint32_t __sh_RDAYAR;
uint32_t __sh_RMONAR;
uint32_t __sh_RCR1;
uint32_t __sh_RCR2;

/* TMU */
uint32_t __sh_TOCR;
uint32_t __sh_TSTR;
uint32_t __sh_TCOR0;
uint32_t __sh_TCNT0;
uint32_t __sh_TCR0;
uint32_t __sh_TCOR1;
uint32_t __sh_TCNT1;
uint32_t __sh_TCR1;
uint32_t __sh_TCOR2;
uint32_t __sh_TCNT2;
uint32_t __sh_TCR2;
uint32_t __sh_TCPR2;

#define	SH3REG(x)	__sh_ ## x = SH3_ ## x
#define	SH4REG(x)	__sh_ ## x = SH4_ ## x

#define	SHREG(x)							\
do {									\
/* Exception */								\
SH ## x ## REG(TRA);							\
SH ## x ## REG(EXPEVT);							\
SH ## x ## REG(INTEVT);							\
/* UBC */								\
SH ## x ## REG(BARA);							\
SH ## x ## REG(BAMRA);							\
SH ## x ## REG(BASRA);							\
SH ## x ## REG(BBRA);							\
SH ## x ## REG(BARB);							\
SH ## x ## REG(BAMRB);							\
SH ## x ## REG(BASRB);							\
SH ## x ## REG(BBRB);							\
SH ## x ## REG(BDRB);							\
SH ## x ## REG(BDMRB);							\
SH ## x ## REG(BRCR);							\
/* MMU */								\
SH ## x ## REG(PTEH);							\
SH ## x ## REG(TEA);							\
SH ## x ## REG(TTB);							\
/* RTC */								\
SH ## x ## REG(R64CNT);							\
SH ## x ## REG(RSECCNT);						\
SH ## x ## REG(RMINCNT);						\
SH ## x ## REG(RHRCNT);							\
SH ## x ## REG(RWKCNT);							\
SH ## x ## REG(RDAYCNT);						\
SH ## x ## REG(RMONCNT);						\
SH ## x ## REG(RYRCNT);							\
SH ## x ## REG(RSECAR);							\
SH ## x ## REG(RMINAR);							\
SH ## x ## REG(RHRAR);							\
SH ## x ## REG(RWKAR);							\
SH ## x ## REG(RDAYAR);							\
SH ## x ## REG(RMONAR);							\
SH ## x ## REG(RCR1);							\
SH ## x ## REG(RCR2);							\
/* TMU */								\
SH ## x ## REG(TOCR);							\
SH ## x ## REG(TSTR);							\
SH ## x ## REG(TCOR0);							\
SH ## x ## REG(TCNT0);							\
SH ## x ## REG(TCR0);							\
SH ## x ## REG(TCOR1);							\
SH ## x ## REG(TCNT1);							\
SH ## x ## REG(TCR1);							\
SH ## x ## REG(TCOR2);							\
SH ## x ## REG(TCNT2);							\
SH ## x ## REG(TCR2);							\
SH ## x ## REG(TCPR2);							\
} while (/*CONSTCOND*/0)

void
sh_devreg_init()
{
	if (CPU_IS_SH3)
		SHREG(3);

	if (CPU_IS_SH4)
		SHREG(4);
}


code:
#	$OpenBSD: genassym.cf,v 1.6 2010/12/14 20:24:25 jasper Exp $
#	$NetBSD: genassym.cf,v 1.10 2005/12/11 12:19:00 christos Exp $

#-
# Copyright (c) 2002 The NetBSD Foundation, Inc.
# 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.
#
# 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.
#

include <sys/param.h>
include <sys/proc.h>
include <sys/signal.h>
include <sys/mbuf.h>
include <sys/user.h>
include <sys/errno.h>
include <uvm/uvm_extern.h>
include <sh/fpu.h>
include <sh/locore.h>
include <sh/reg.h>
include <sh/vmparam.h>
include <sh/pte.h>

struct	trapframe
define	TF_SIZE			sizeof(struct trapframe)
member	tf_expevt
member	tf_ubc
member	tf_spc

struct	proc
member	p_addr
member	p_stat
member	p_wchan
member	P_MD_UPTE	p_md.md_upte
member	P_MD_PCB	p_md.md_pcb

struct	switchframe
define	SF_SIZE			sizeof(struct switchframe)
member	sf_r15
member	sf_r6_bank
member	sf_r7_bank

struct	fpreg
define	FP_SIZE			sizeof(struct fpreg)

struct	pcb
member	pcb_onfault
member	pcb_fp

export	SONPROC
export	SRUN

struct	uvmexp		UVMEXP_
member	intrs

export	VM_MAXUSER_ADDRESS
export	VM_MIN_KERNEL_ADDRESS

export	EFAULT
export	ENAMETOOLONG

#
# in_cksum.S
#
struct	mbuf
member	m_data
member	m_len
member	m_next

struct cpu_info
member ci_curproc


code:
/*	$OpenBSD: in_cksum.S,v 1.2 2006/11/10 19:23:35 miod Exp $	*/
/*	$NetBSD: in_cksum.S,v 1.10 2006/04/11 23:45:13 uwe Exp $	*/

/*-
 * Copyright (c) 2000 SHIMIZU Ryo <ryo@misakimix.org>
 * 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. 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 <machine/asm.h>
#include "assym.h"

#define	reg_tmp0		r0
#define	reg_byte_swapped	r1
#define	reg_mlen		r2
#define	reg_tmp3		r3
#define	reg_m			r4
#define	reg_len			r5
#define	reg_sum			r6
#define	reg_w			r7

#define	REDUCE	\
	swap.w	reg_sum,reg_tmp0	; \
	extu.w	reg_sum,reg_sum		; \
	extu.w	reg_tmp0,reg_tmp0	; \
	add	reg_tmp0,reg_sum

#define	ROL	\
	shll8	reg_sum

#ifndef __LITTLE_ENDIAN__
#define	ADDB	\
	mov.b	@reg_w+,reg_tmp0	; \
	ROL				; \
	extu.b	reg_tmp0,reg_tmp0	; \
	add	reg_tmp0,reg_sum	; \
	not	reg_byte_swapped,reg_byte_swapped
#else
#define	ADDB	\
	mov.b	@reg_w+,reg_tmp0	; \
	extu.b	reg_tmp0,reg_tmp0	; \
	add	reg_tmp0,reg_sum	; \
	ROL				; \
	not	reg_byte_swapped,reg_byte_swapped
#endif

#define	ADDS	\
	mov.w	@reg_w+,reg_tmp0	; \
	extu.w	reg_tmp0,reg_tmp0	; \
	add	reg_tmp0,reg_sum

#define	ADDCL	\
	mov.l	@reg_w+,reg_tmp0	; \
	addc	reg_tmp0,reg_sum

#define	FORWARD1	\
	add	#-1,reg_mlen

#define	FORWARD2	\
	add	#-2,reg_mlen

/*
 * LINTSTUB: include <sys/param.h>
 * LINTSTUB: include <sys/mbuf.h>
 *
 * LINTSTUB: Func: int in_cksum(struct mbuf *m, int len);
 */
ENTRY(in_cksum)
	sts.l	pr,@-sp

	mov	#0,reg_sum
	mov	#0,reg_byte_swapped

	tst	reg_len,reg_len
	bt/s	mbuf_loop_done
mbuf_loop:
	tst	reg_m,reg_m
	bt	mbuf_loop_done

	mov.l	@(M_LEN,reg_m),reg_mlen
	tst	reg_mlen,reg_mlen
	bt/s	mbuf_loop_continue
	mov.l	@(M_DATA,reg_m),reg_w

	cmp/ge	reg_mlen,reg_len
	bt	1f
	mov	reg_len,reg_mlen
1:
	sub	reg_mlen,reg_len

	mov	reg_w,reg_tmp0
	tst	#1,reg_tmp0
	bt/s	1f
	REDUCE		/* 1st instruction break only reg_tmp0(r0) */
	ADDB
	FORWARD1
1:

	mov	#1,reg_tmp0
	cmp/gt	reg_tmp0,reg_mlen
	bf/s	1f
	mov	reg_w,reg_tmp0
	tst	#2,reg_tmp0
	bt/s	1f
	REDUCE		/* 1st instruction break only reg_tmp0(r0) */
	ADDS
	FORWARD2
1:

	mov	#127,reg_tmp0
	cmp/hi	reg_tmp0,reg_mlen
	bf	1f

do_cksum128:
	bsr	cksum128
	 nop

	mov	#127,reg_tmp0
	cmp/hi	reg_tmp0,reg_mlen
	bt	do_cksum128
1:

	bsr	cksum128mod
	 nop

	REDUCE

	mov	#1,reg_tmp0
	cmp/gt	reg_tmp0,reg_mlen
	bf	1f
	ADDS
	FORWARD2
1:

	mov	reg_mlen,r0
	tst	#1,r0
	bt	1f
	ADDB
1:

mbuf_loop_continue:
	mov.l	@(M_NEXT,reg_m),reg_m

	tst	reg_len,reg_len
	bf/s	mbuf_loop
mbuf_loop_done:

	tst	reg_byte_swapped,reg_byte_swapped
	bt/s	1f
	REDUCE		/* 1st instruction break only reg_tmp0(r0) */
	ROL
1:

	REDUCE
	REDUCE

in_cksum_return:
	not	reg_sum,r0
	lds.l	@sp+,pr
	rts
	 extu.w	r0,r0

	SET_ENTRY_SIZE(in_cksum)

	.align	2
cksum128mod:
	mov	reg_mlen,reg_tmp0
	and	#124,reg_tmp0
	sub	reg_tmp0,reg_mlen

	mov.l	.L_cksum128_tail_p,reg_tmp3
	sub	reg_tmp0,reg_tmp3
	jmp	@reg_tmp3
	 clrt

	.align	2
.L_cksum128_tail_p:
	.long	cksum128_tail

	.align	2
cksum128:
	add	#-128,reg_mlen
	clrt

cksum128_unroll:
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
	ADDCL
cksum128_tail:
	mov	#0,reg_tmp0
	rts
	 addc	reg_tmp0,reg_sum


code:
/*	$OpenBSD: interrupt.c,v 1.14 2014/07/12 18:44:42 tedu Exp $	*/
/*	$NetBSD: interrupt.c,v 1.18 2006/01/25 00:02:57 uwe Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>	/* uvmexp.intrs */

#include <sh/clock.h>
#include <sh/trap.h>
#include <sh/intcreg.h>
#include <sh/tmureg.h>
#include <machine/atomic.h>
#include <machine/intr.h>

void intc_intr_priority(int, int);
struct intc_intrhand *intc_alloc_ih(void);
void intc_free_ih(struct intc_intrhand *);
int intc_unknown_intr(void *);

#ifdef SH4
void intpri_intr_enable(int);
void intpri_intr_disable(int);
#endif

void netintr(void);
void tmu1_oneshot(void);
int tmu1_intr(void *);
void setsoft(int);

/*
 * EVTCODE to intc_intrhand mapper.
 * max #76 is SH4_INTEVT_TMU4 (0xb80)
 */
int8_t __intc_evtcode_to_ih[128];

struct intc_intrhand __intc_intrhand[_INTR_N + 1] = {
	/* Place holder interrupt handler for unregistered interrupt. */
	[0] = { .ih_func = intc_unknown_intr, .ih_level = 0xf0 }
};

struct sh_soft_intr sh_soft_intrs[_IPL_NSOFT];

/*
 * SH INTC support.
 */
void
intc_init(void)
{

	switch (cpu_product) {
#ifdef SH3
	case CPU_PRODUCT_7709:
	case CPU_PRODUCT_7709A:
		_reg_write_2(SH7709_IPRC, 0);
		_reg_write_2(SH7709_IPRD, 0);
		_reg_write_2(SH7709_IPRE, 0);
		/* FALLTHROUGH */
	case CPU_PRODUCT_7708:
	case CPU_PRODUCT_7708S:
	case CPU_PRODUCT_7708R:
		_reg_write_2(SH3_IPRA, 0);
		_reg_write_2(SH3_IPRB, 0);
		break;
#endif /* SH3 */

#ifdef SH4
	case CPU_PRODUCT_7751:
	case CPU_PRODUCT_7751R:
		_reg_write_4(SH4_INTPRI00, 0);
		_reg_write_4(SH4_INTMSK00, INTMSK00_MASK_ALL);
		/* FALLTHROUGH */
	case CPU_PRODUCT_7750S:
	case CPU_PRODUCT_7750R:
		_reg_write_2(SH4_IPRD, 0);
		/* FALLTHROUGH */
	case CPU_PRODUCT_7750:
		_reg_write_2(SH4_IPRA, 0);
		_reg_write_2(SH4_IPRB, 0);
		_reg_write_2(SH4_IPRC, 0);
		break;
#endif /* SH4 */
	}
}

void *
intc_intr_establish(int evtcode, int trigger, int level,
    int (*ih_func)(void *), void *ih_arg, const char *name)
{
	struct intc_intrhand *ih;

	KDASSERT(evtcode >= 0x200 && level > 0);

	ih = intc_alloc_ih();
	ih->ih_func	= ih_func;
	ih->ih_arg	= ih_arg;
	ih->ih_level	= level << 4;	/* convert to SR.IMASK format. */
	ih->ih_evtcode	= evtcode;
	ih->ih_irq	= evtcode >> 5;
	ih->ih_name	= name;
	if (name)
		evcount_attach(&ih->ih_count, name, &ih->ih_irq);

	/* Map interrupt handler */
	EVTCODE_TO_IH_INDEX(evtcode) = ih->ih_idx;

	/* Priority */
	intc_intr_priority(evtcode, level);

	/* Sense select (SH7709, SH7709A only) XXX notyet */

	return (ih);
}

void
intc_intr_disestablish(void *arg)
{
	struct intc_intrhand *ih = arg;
	int evtcode = ih->ih_evtcode;

	/* Mask interrupt if IPR can manage it. if not, cascaded ICU will do */
	intc_intr_priority(evtcode, 0);

	/* Unmap interrupt handler */
	EVTCODE_TO_IH_INDEX(evtcode) = 0;

	if (ih->ih_name)
		evcount_detach(&ih->ih_count);
	intc_free_ih(ih);
}

void
intc_intr_disable(int evtcode)
{
	int s;

	s = _cpu_intr_suspend();
	KASSERT(EVTCODE_TO_IH_INDEX(evtcode) != 0); /* there is a handler */
	switch (evtcode) {
	default:
		intc_intr_priority(evtcode, 0);
		break;

#ifdef SH4
	case SH4_INTEVT_PCISERR:
	case SH4_INTEVT_PCIDMA3:
	case SH4_INTEVT_PCIDMA2:
	case SH4_INTEVT_PCIDMA1:
	case SH4_INTEVT_PCIDMA0:
	case SH4_INTEVT_PCIPWON:
	case SH4_INTEVT_PCIPWDWN:
	case SH4_INTEVT_PCIERR:
		intpri_intr_disable(evtcode);
		break;
#endif
	}
	_cpu_intr_resume(s);
}

void
intc_intr_enable(int evtcode)
{
	struct intc_intrhand *ih;
	int s;

	s = _cpu_intr_suspend();
	KASSERT(EVTCODE_TO_IH_INDEX(evtcode) != 0); /* there is a handler */
	switch (evtcode) {
	default:
		ih = EVTCODE_IH(evtcode);
		/* ih_level is in the SR.IMASK format */
		intc_intr_priority(evtcode, (ih->ih_level >> 4));
		break;

#ifdef SH4
	case SH4_INTEVT_PCISERR:
	case SH4_INTEVT_PCIDMA3:
	case SH4_INTEVT_PCIDMA2:
	case SH4_INTEVT_PCIDMA1:
	case SH4_INTEVT_PCIDMA0:
	case SH4_INTEVT_PCIPWON:
	case SH4_INTEVT_PCIPWDWN:
	case SH4_INTEVT_PCIERR:
		intpri_intr_enable(evtcode);
		break;
#endif
	}
	_cpu_intr_resume(s);
}

/*
 * int intc_intr_priority(int evtcode, int level)
 *	Setup interrupt priority register.
 *	SH7708, SH7708S, SH7708R, SH7750, SH7750S ... evtcode is INTEVT
 *	SH7709, SH7709A				  ... evtcode is INTEVT2
 */
void
intc_intr_priority(int evtcode, int level)
{
	volatile uint16_t *iprreg;
	int pos;
	uint16_t r;

#define	__SH_IPR(_sh, _ipr, _pos)					   \
	do {								   \
		iprreg = (volatile uint16_t *)(SH ## _sh ## _IPR ## _ipr); \
		pos = (_pos);						   \
	} while (/*CONSTCOND*/0)

#define	SH3_IPR(_ipr, _pos)		__SH_IPR(3, _ipr, _pos)
#define	SH4_IPR(_ipr, _pos)		__SH_IPR(4, _ipr, _pos)
#define	SH7709_IPR(_ipr, _pos)		__SH_IPR(7709, _ipr, _pos)

#define	SH_IPR(_ipr, _pos)						\
	do {								\
		if (CPU_IS_SH3)						\
			SH3_IPR(_ipr, _pos);				\
		else							\
			SH4_IPR(_ipr, _pos);				\
	} while (/*CONSTCOND*/0)

	iprreg = 0;
	pos = -1;

	switch (evtcode) {
	case SH_INTEVT_TMU0_TUNI0:
		SH_IPR(A, 12);
		break;
	case SH_INTEVT_TMU1_TUNI1:
		SH_IPR(A, 8);
		break;
	case SH_INTEVT_TMU2_TUNI2:
		SH_IPR(A, 4);
		break;
	case SH_INTEVT_WDT_ITI:
		SH_IPR(B, 12);
		break;
	case SH_INTEVT_SCI_ERI:
	case SH_INTEVT_SCI_RXI:
	case SH_INTEVT_SCI_TXI:
	case SH_INTEVT_SCI_TEI:
		SH_IPR(B, 4);
		break;
	}

#ifdef SH3
	if (CPU_IS_SH3) {
		switch (evtcode) {
		case SH7709_INTEVT2_IRQ3:
			SH7709_IPR(C, 12);
			break;
		case SH7709_INTEVT2_IRQ2:
			SH7709_IPR(C, 8);
			break;
		case SH7709_INTEVT2_IRQ1:
			SH7709_IPR(C, 4);
			break;
		case SH7709_INTEVT2_IRQ0:
			SH7709_IPR(C, 0);
			break;
		case SH7709_INTEVT2_PINT07:
			SH7709_IPR(D, 12);
			break;
		case SH7709_INTEVT2_PINT8F:
			SH7709_IPR(D, 8);
			break;
		case SH7709_INTEVT2_IRQ5:
			SH7709_IPR(D, 4);
			break;
		case SH7709_INTEVT2_IRQ4:
			SH7709_IPR(D, 0);
			break;
		case SH7709_INTEVT2_DEI0:
		case SH7709_INTEVT2_DEI1:
		case SH7709_INTEVT2_DEI2:
		case SH7709_INTEVT2_DEI3:
			SH7709_IPR(E, 12);
			break;
		case SH7709_INTEVT2_IRDA_ERI:
		case SH7709_INTEVT2_IRDA_RXI:
		case SH7709_INTEVT2_IRDA_BRI:
		case SH7709_INTEVT2_IRDA_TXI:
			SH7709_IPR(E, 8);
			break;
		case SH7709_INTEVT2_SCIF_ERI:
		case SH7709_INTEVT2_SCIF_RXI:
		case SH7709_INTEVT2_SCIF_BRI:
		case SH7709_INTEVT2_SCIF_TXI:
			SH7709_IPR(E, 4);
			break;
		case SH7709_INTEVT2_ADC:
			SH7709_IPR(E, 0);
			break;
		}
	}
#endif /* SH3 */

#ifdef SH4
	if (CPU_IS_SH4) {
		switch (evtcode) {
		case SH4_INTEVT_SCIF_ERI:
		case SH4_INTEVT_SCIF_RXI:
		case SH4_INTEVT_SCIF_BRI:
		case SH4_INTEVT_SCIF_TXI:
			SH4_IPR(C, 4);
			break;

#if 0
		case SH4_INTEVT_PCISERR:
		case SH4_INTEVT_PCIDMA3:
		case SH4_INTEVT_PCIDMA2:
		case SH4_INTEVT_PCIDMA1:
		case SH4_INTEVT_PCIDMA0:
		case SH4_INTEVT_PCIPWON:
		case SH4_INTEVT_PCIPWDWN:
		case SH4_INTEVT_PCIERR:
#endif
		case SH4_INTEVT_TMU3:
		case SH4_INTEVT_TMU4:
			intpri_intr_priority(evtcode, level);
			break;
		}
	}
#endif /* SH4 */

	/*
	 * XXX: This function gets called even for interrupts that
	 * don't have their priority defined by IPR registers.
	 */
	if (pos < 0)
		return;

	r = _reg_read_2(iprreg);
	r = (r & ~(0xf << (pos))) | (level << (pos));
	_reg_write_2(iprreg, r);
}

/*
 * Interrupt handler holder allocater.
 */
struct intc_intrhand *
intc_alloc_ih(void)
{
	/* #0 is reserved for unregistered interrupt. */
	struct intc_intrhand *ih = &__intc_intrhand[1];
	int i;

	for (i = 1; i <= _INTR_N; i++, ih++)
		if (ih->ih_idx == 0) {	/* no driver uses this. */
			ih->ih_idx = i;	/* register myself */
			return (ih);
		}

	panic("increase _INTR_N greater than %d", _INTR_N);
	return (NULL);
}

void
intc_free_ih(struct intc_intrhand *ih)
{
	ih->ih_idx = 0;
	memset(ih, 0, sizeof(*ih));
}

/* Place-holder for debugging */
int
intc_unknown_intr(void *arg)
{
	printf("INTEVT=0x%x", _reg_read_4(SH_(INTEVT)));
	if (cpu_product == CPU_PRODUCT_7709 || cpu_product == CPU_PRODUCT_7709A)
		printf(" INTEVT2=0x%x", _reg_read_4(SH7709_INTEVT2));
	printf("\n");

	panic("unknown interrupt");
	/* NOTREACHED */
	return (0);
}

#ifdef SH4 /* SH7751 support */

/*
 * INTPRIxx
 */
void
intpri_intr_priority(int evtcode, int level)
{
	volatile uint32_t *iprreg;
	uint32_t r;
	int pos;

	if (!CPU_IS_SH4)
		return;

	switch (cpu_product) {
	default:
		return;

	case CPU_PRODUCT_7751:
	case CPU_PRODUCT_7751R:
		break;
	}

	iprreg = (volatile uint32_t *)SH4_INTPRI00;
	pos = -1;

	switch (evtcode) {
	case SH4_INTEVT_PCIDMA3:
	case SH4_INTEVT_PCIDMA2:
	case SH4_INTEVT_PCIDMA1:
	case SH4_INTEVT_PCIDMA0:
	case SH4_INTEVT_PCIPWDWN:
	case SH4_INTEVT_PCIPWON:
	case SH4_INTEVT_PCIERR:
		pos = 0;
		break;

	case SH4_INTEVT_PCISERR:
		pos = 4;
		break;

	case SH4_INTEVT_TMU3:
		pos = 8;
		break;

	case SH4_INTEVT_TMU4:
		pos = 12;
		break;
	}

	if (pos < 0) {
		return;
	}

	r = _reg_read_4(iprreg);
	r = (r & ~(0xf << pos)) | (level << pos);
	_reg_write_4(iprreg, r);
}

void
intpri_intr_enable(int evtcode)
{
	volatile uint32_t *iprreg;
	uint32_t bit;

	if (!CPU_IS_SH4)
		return;

	switch (cpu_product) {
	default:
		return;

	case CPU_PRODUCT_7751:
	case CPU_PRODUCT_7751R:
		break;
	}

	iprreg = (volatile uint32_t *)SH4_INTMSKCLR00;
	bit = 0;

	switch (evtcode) {
	case SH4_INTEVT_PCISERR:
	case SH4_INTEVT_PCIDMA3:
	case SH4_INTEVT_PCIDMA2:
	case SH4_INTEVT_PCIDMA1:
	case SH4_INTEVT_PCIDMA0:
	case SH4_INTEVT_PCIPWON:
	case SH4_INTEVT_PCIPWDWN:
	case SH4_INTEVT_PCIERR:
		bit = (1 << ((evtcode - SH4_INTEVT_PCISERR) >> 5));
		break;

	case SH4_INTEVT_TMU3:
		bit = INTREQ00_TUNI3;
		break;

	case SH4_INTEVT_TMU4:
		bit = INTREQ00_TUNI4;
		break;
	}

	if ((bit == 0) || (iprreg == NULL)) {
		return;
	}

	_reg_write_4(iprreg, bit);
}

void
intpri_intr_disable(int evtcode)
{
	volatile uint32_t *iprreg;
	uint32_t bit;

	if (!CPU_IS_SH4)
		return;

	switch (cpu_product) {
	default:
		return;

	case CPU_PRODUCT_7751:
	case CPU_PRODUCT_7751R:
		break;
	}

	iprreg = (volatile uint32_t *)SH4_INTMSK00;
	bit = 0;

	switch (evtcode) {
	case SH4_INTEVT_PCISERR:
	case SH4_INTEVT_PCIDMA3:
	case SH4_INTEVT_PCIDMA2:
	case SH4_INTEVT_PCIDMA1:
	case SH4_INTEVT_PCIDMA0:
	case SH4_INTEVT_PCIPWON:
	case SH4_INTEVT_PCIPWDWN:
	case SH4_INTEVT_PCIERR:
		bit = (1 << ((evtcode - SH4_INTEVT_PCISERR) >> 5));
		break;

	case SH4_INTEVT_TMU3:
		bit = INTREQ00_TUNI3;
		break;

	case SH4_INTEVT_TMU4:
		bit = INTREQ00_TUNI4;
		break;
	}

	if ((bit == 0) || (iprreg == NULL)) {
		return;
	}

	_reg_write_4(iprreg, bit);
}
#endif /* SH4 */

/*
 * Software interrupt support
 */
void
softintr_init(void)
{
	struct sh_soft_intr *asi;
	int i;

	for (i = 0; i < _IPL_NSOFT; i++) {
		asi = &sh_soft_intrs[i];
		TAILQ_INIT(&asi->softintr_q);
		mtx_init(&asi->softintr_lock, IPL_HIGH);
		asi->softintr_ipl = IPL_SOFT + i;
	}

	intc_intr_establish(SH_INTEVT_TMU1_TUNI1, IST_LEVEL, IPL_SOFTNET,
	    tmu1_intr, NULL, "tmu1");
}

void
softintr_dispatch(int ipl)
{
	struct sh_soft_intr *asi;
	struct sh_soft_intrhand *sih;

	asi = &sh_soft_intrs[ipl - IPL_SOFT];

	for (;;) {
		mtx_enter(&asi->softintr_lock);
		sih = TAILQ_FIRST(&asi->softintr_q);
		if (sih == NULL) {
			mtx_leave(&asi->softintr_lock);
			break;
		}
		TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
		sih->sih_pending = 0;

		uvmexp.softs++;
		mtx_leave(&asi->softintr_lock);

		(*sih->sih_fn)(sih->sih_arg);
	}
}

void
setsoft(int ipl)
{
	tmu1_oneshot();
}

/* Register a software interrupt handler. */
void *
softintr_establish(int ipl, void (*func)(void *), void *arg)
{
	struct sh_soft_intr *asi;
	struct sh_soft_intrhand *sih;

	if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) ||
			    ipl < IPL_SOFT))
		panic("softintr_establish");

	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);

	asi = &sh_soft_intrs[ipl - IPL_SOFT];
	if (__predict_true(sih != NULL)) {
		sih->sih_intrhead = asi;
		sih->sih_fn = func;
		sih->sih_arg = arg;
		sih->sih_pending = 0;
	}

	return (sih);
}

/* Unregister a software interrupt handler. */
void
softintr_disestablish(void *arg)
{
	struct sh_soft_intrhand *sih = arg;
	struct sh_soft_intr *asi = sih->sih_intrhead;

	mtx_enter(&asi->softintr_lock);
	if (sih->sih_pending) {
		TAILQ_REMOVE(&asi->softintr_q, sih, sih_q);
		sih->sih_pending = 0;
	}
	mtx_leave(&asi->softintr_lock);

	free(sih, M_DEVBUF, 0);
}

/* Schedule a software interrupt. */
void softintr_schedule(void *arg)
{
	struct sh_soft_intrhand *sih = arg;
	struct sh_soft_intr *si = sih->sih_intrhead;

	mtx_enter(&si->softintr_lock);
	if (sih->sih_pending == 0) {
		TAILQ_INSERT_TAIL(&si->softintr_q, sih, sih_q);
		sih->sih_pending = 1;
		setsoft(si->softintr_ipl);
	}
	mtx_leave(&si->softintr_lock);
}

/*
 * Software interrupt is simulated with TMU one-shot timer.
 */
void
tmu1_oneshot(void)
{
	_reg_bclr_1(SH_(TSTR), TSTR_STR1);
	_reg_write_4(SH_(TCNT1), 0);
	_reg_bset_1(SH_(TSTR), TSTR_STR1);
}

int
tmu1_intr(void *arg)
{
	_reg_bclr_1(SH_(TSTR), TSTR_STR1);
	_reg_bclr_2(SH_(TCR1), TCR_UNF);

	softintr_dispatch(IPL_SOFTSERIAL);
	softintr_dispatch(IPL_SOFTNET);
	softintr_dispatch(IPL_SOFTCLOCK);
	softintr_dispatch(IPL_SOFT);

	return (0);
}


code:
/*	$OpenBSD: locore_c.c,v 1.12 2014/11/18 20:51:01 krw Exp $	*/
/*	$NetBSD: locore_c.c,v 1.13 2006/03/04 01:13:35 uwe Exp $	*/

/*-
 * Copyright (c) 1996, 1997, 2002 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.
 */

/*-
 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz.
 *
 * 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.
 *
 *	@(#)Locore.c
 */

/*-
 * Copyright (c) 1993, 1994, 1995, 1996, 1997
 *	 Charles M. Hannum.  All rights reserved.
 * Copyright (c) 1992 Terrence R. Lambert.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz.
 *
 * 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 by the University of
 *	California, Berkeley and its contributors.
 * 4. 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.
 *
 *	@(#)Locore.c
 */

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

#include <uvm/uvm_extern.h>

#include <sh/locore.h>
#include <sh/cpu.h>
#include <sh/pcb.h>
#include <sh/pmap.h>
#include <sh/mmu_sh3.h>
#include <sh/mmu_sh4.h>
#include <sh/ubcreg.h>

void (*__sh_switch_resume)(struct proc *);
void cpu_switch_prepare(struct proc *, struct proc *);
int want_resched;

/*
 * Prepare context switch from oproc to nproc.
 * This code is used by cpu_switchto.
 */
void
cpu_switch_prepare(struct proc *oproc, struct proc *nproc)
{
	nproc->p_stat = SONPROC;

	if (oproc && (oproc->p_md.md_flags & MDP_STEP))
		_reg_write_2(SH_(BBRB), 0);

	curpcb = nproc->p_md.md_pcb;
	pmap_activate(nproc);

	if (nproc->p_md.md_flags & MDP_STEP) {
		int pm_asid = nproc->p_vmspace->vm_map.pmap->pm_asid;

		_reg_write_2(SH_(BBRB), 0);
		_reg_write_4(SH_(BARB), nproc->p_md.md_regs->tf_spc);
		_reg_write_1(SH_(BASRB), pm_asid);
		_reg_write_1(SH_(BAMRB), 0);
		_reg_write_2(SH_(BRCR), 0x0040);
		_reg_write_2(SH_(BBRB), 0x0014);
	}

	curproc = nproc;
}

void
cpu_exit(struct proc *p)
{
	if (p->p_md.md_flags & MDP_STEP)
		_reg_write_2(SH_(BBRB), 0);

	pmap_deactivate(p);
	sched_exit(p);
}

#ifndef P1_STACK
#ifdef SH3
/*
 * void sh3_switch_setup(struct proc *p):
 *	prepare kernel stack PTE table. TLB miss handler check these.
 */
void
sh3_switch_setup(struct proc *p)
{
	pt_entry_t *pte;
	struct md_upte *md_upte = p->p_md.md_upte;
	uint32_t vpn;
	int i;

	vpn = (uint32_t)p->p_addr;
	vpn &= ~PGOFSET;
	for (i = 0; i < UPAGES; i++, vpn += PAGE_SIZE, md_upte++) {
		pte = __pmap_kpte_lookup(vpn);
		KDASSERT(pte && *pte != 0);

		md_upte->addr = vpn;
		md_upte->data = (*pte & PG_HW_BITS) | PG_D | PG_V;
	}
}
#endif /* SH3 */

#ifdef SH4
/*
 * void sh4_switch_setup(struct proc *p):
 *	prepare kernel stack PTE table. sh4_switch_resume wired this PTE.
 */
void
sh4_switch_setup(struct proc *p)
{
	pt_entry_t *pte;
	struct md_upte *md_upte = p->p_md.md_upte;
	uint32_t vpn;
	int i, e;

	vpn = (uint32_t)p->p_addr;
	vpn &= ~PGOFSET;
	e = SH4_UTLB_ENTRY - UPAGES;
	for (i = 0; i < UPAGES; i++, e++, vpn += PAGE_SIZE) {
		pte = __pmap_kpte_lookup(vpn);
		KDASSERT(pte && *pte != 0);
		/* Address array */
		md_upte->addr = SH4_UTLB_AA | (e << SH4_UTLB_E_SHIFT);
		md_upte->data = vpn | SH4_UTLB_AA_D | SH4_UTLB_AA_V;
		md_upte++;
		/* Data array */
		md_upte->addr = SH4_UTLB_DA1 | (e << SH4_UTLB_E_SHIFT);
		md_upte->data = (*pte & PG_HW_BITS) |
		    SH4_UTLB_DA1_D | SH4_UTLB_DA1_V;
		md_upte++;
	}
}
#endif /* SH4 */
#endif /* !P1_STACK */

/*
 * copystr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
 * Copy a NUL-terminated string, at most maxlen characters long.  Return the
 * number of characters copied (including the NUL) in *lencopied.  If the
 * string is too long, return ENAMETOOLONG; else return 0.
 */
int
copystr(const void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied)
{
	const char *from = kfaddr;
	char *to = kdaddr;
	int i;

	for (i = 0; maxlen-- > 0; i++) {
		if ((*to++ = *from++) == '\0') {
			if (lencopied)
				*lencopied = i + 1;
			return (0);
		}
	}

	if (lencopied)
		*lencopied = i;

	return (ENAMETOOLONG);
}


code:
/*	$OpenBSD: locore_subr.S,v 1.10 2010/09/06 08:00:31 jsg Exp $	*/
/*	$NetBSD: locore_subr.S,v 1.28 2006/01/23 22:52:09 uwe Exp $	*/

/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice, this permission notice, and the disclaimer below
 * appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * 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.
 *
 * 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.
 */

#include "assym.h"

#include <sys/syscall.h>	/* SYS_sigreturn, SYS_exit */
#include <sh/asm.h>
#include <sh/locore.h>
#include <sh/param.h>		/* UPAGES */
#include <sh/mmu_sh3.h>
#include <sh/mmu_sh4.h>

/*
 * LINTSTUB: include <sys/types.h>
 * LINTSTUB: include <sys/proc.h>
 * LINTSTUB: include <sh/locore.h>
 */

/*
 * Save integer registers in the pcb.
 * reg points to pcb->pcb_sf.
 */
#define	SAVEPCB(reg) \
	add	#SF_SIZE, reg ; \
	sts.l	mach,	@-##reg ; \
	sts.l	macl,	@-##reg ; \
	stc.l	r7_bank,@-##reg ; \
	stc.l	sr,	@-##reg ; \
	stc.l	r6_bank,@-##reg ; \
	sts.l	pr,	@-##reg ; \
	mov.l	r8,	@-##reg ; \
	mov.l	r9,	@-##reg ; \
	mov.l	r10,	@-##reg ; \
	mov.l	r11,	@-##reg ; \
	mov.l	r12,	@-##reg ; \
	mov.l	r13,	@-##reg ; \
	mov.l	r14,	@-##reg ; \
	mov.l	r15,	@-##reg

/*
 * Save floating point registers to a fpreg structure.
 * reg points to the structure, tmp and tmp2 are two scratch integer registers.
 */
#define	SAVEFP(reg, tmp, tmp2) \
	add	#124,	reg ; \
	sts	fpscr,	tmp2 ; \
	add	#(FP_SIZE - 124), reg ; \
	mov	#0,	tmp; \
	mov.l	tmp2,	@-##reg ; \
	lds	tmp,	fpscr; \
	sts.l	fpul,	@-##reg ; \
	frchg; \
	fmov.s	fr15,	@-##reg ; \
	fmov.s	fr14,	@-##reg ; \
	fmov.s	fr13,	@-##reg ; \
	fmov.s	fr12,	@-##reg ; \
	fmov.s	fr11,	@-##reg ; \
	fmov.s	fr10,	@-##reg ; \
	fmov.s	fr9,	@-##reg ; \
	fmov.s	fr8,	@-##reg ; \
	fmov.s	fr7,	@-##reg ; \
	fmov.s	fr6,	@-##reg ; \
	fmov.s	fr5,	@-##reg ; \
	fmov.s	fr4,	@-##reg ; \
	fmov.s	fr3,	@-##reg ; \
	fmov.s	fr2,	@-##reg ; \
	fmov.s	fr1,	@-##reg ; \
	fmov.s	fr0,	@-##reg ; \
	frchg; \
	fmov.s	fr15,	@-##reg ; \
	fmov.s	fr14,	@-##reg ; \
	fmov.s	fr13,	@-##reg ; \
	fmov.s	fr12,	@-##reg ; \
	fmov.s	fr11,	@-##reg ; \
	fmov.s	fr10,	@-##reg ; \
	fmov.s	fr9,	@-##reg ; \
	fmov.s	fr8,	@-##reg ; \
	fmov.s	fr7,	@-##reg ; \
	fmov.s	fr6,	@-##reg ; \
	fmov.s	fr5,	@-##reg ; \
	fmov.s	fr4,	@-##reg ; \
	fmov.s	fr3,	@-##reg ; \
	fmov.s	fr2,	@-##reg ; \
	fmov.s	fr1,	@-##reg ; \
	fmov.s	fr0,	@-##reg ; \
	lds	tmp2,	fpscr

/*
 * Load floating point registers from a fpreg structure.
 * reg points to the structure, tmp is a scratch integer register.
 */
#define	LOADFP(reg, tmp) \
	mov	#0,	tmp; \
	lds	tmp,	fpscr; \
	fmov.s	@##reg##+, fr0 ; \
	fmov.s	@##reg##+, fr1 ; \
	fmov.s	@##reg##+, fr2 ; \
	fmov.s	@##reg##+, fr3 ; \
	fmov.s	@##reg##+, fr4 ; \
	fmov.s	@##reg##+, fr5 ; \
	fmov.s	@##reg##+, fr6 ; \
	fmov.s	@##reg##+, fr7 ; \
	fmov.s	@##reg##+, fr8 ; \
	fmov.s	@##reg##+, fr9 ; \
	fmov.s	@##reg##+, fr10 ; \
	fmov.s	@##reg##+, fr11 ; \
	fmov.s	@##reg##+, fr12 ; \
	fmov.s	@##reg##+, fr13 ; \
	fmov.s	@##reg##+, fr14 ; \
	fmov.s	@##reg##+, fr15 ; \
	frchg; \
	fmov.s	@##reg##+, fr0 ; \
	fmov.s	@##reg##+, fr1 ; \
	fmov.s	@##reg##+, fr2 ; \
	fmov.s	@##reg##+, fr3 ; \
	fmov.s	@##reg##+, fr4 ; \
	fmov.s	@##reg##+, fr5 ; \
	fmov.s	@##reg##+, fr6 ; \
	fmov.s	@##reg##+, fr7 ; \
	fmov.s	@##reg##+, fr8 ; \
	fmov.s	@##reg##+, fr9 ; \
	fmov.s	@##reg##+, fr10 ; \
	fmov.s	@##reg##+, fr11 ; \
	fmov.s	@##reg##+, fr12 ; \
	fmov.s	@##reg##+, fr13 ; \
	fmov.s	@##reg##+, fr14 ; \
	fmov.s	@##reg##+, fr15 ; \
	lds.l	@##reg##+, fpul ; \
	lds.l	@##reg##+, fpscr

	.text
	.align 5	/* align cache line size (32B) */
/*
 * LINTSTUB: Func: void cpu_switchto(struct proc *old, struct proc *new)
 *	Switch proc contexts.
 */
ENTRY(cpu_switchto)
	mov	r4,	r0
	cmp/eq	#0,	r0
	bt	1f

	/* Save old proc's context to switchframe */
	mov.l	.L_SF,	r0
	mov.l	@(r0, r4), r1
	SAVEPCB(r1)
	add	#PCB_FP, r1
	SAVEFP(r1, r8, r9)

1:
	mov.l	.L_cpu_switch_prepare, r0
	jsr	@r0
	 mov	r5,	r8	/* save new proc */
	mov	r8,	r4

	/* Setup kernel stack */
	mov.l	.L_SF,	r0
	mov.l	@(r0, r4), r1		/* switch frame */
	mov.l	@(SF_R7_BANK, r1), r0	/* stack top */
	mov.l	@(SF_R6_BANK, r1), r2	/* current frame */
	mov.l	@(SF_R15, r1), r3	/* current stack */
	/* During kernel stack switching, all interrupts are disabled. */
	__EXCEPTION_BLOCK(r1, r5)
	/* switch to new kernel stack */
	ldc	r0,	r7_bank
	ldc	r2,	r6_bank
	mov	r3,	r15

	/* Wire u-area */
	MOV	(switch_resume, r0)
	jsr	@r0
	 mov	r4,	r8	/* save new proc */
	mov	r8,	r4
	__EXCEPTION_UNBLOCK(r0, r1)
	/* Now OK to use kernel stack. */

	/* Restore new proc's context from switchframe */
	mov.l	.L_SF,	r0
	mov.l	@(r0, r4), r1
	add	#4,	r1		/* r15 already restored */
	mov.l	@r1+,	r14
	mov.l	@r1+,	r13
	mov.l	@r1+,	r12
	mov.l	@r1+,	r11
	mov.l	@r1+,	r10
	mov.l	@r1+,	r9
	mov.l	@r1+,	r8
	lds.l	@r1+,	pr
	add	#4,	r1		/* r6_bank already restored */
	ldc.l	@r1+,	sr
	add	#4,	r1		/* r7_bank already restored */
	lds.l	@r1+,	macl
	lds.l	@r1+,	mach

	mov.l	@(r0, r4), r1
	add	#PCB_FP, r1
	LOADFP(r1, r0)
	rts
	 nop
	.align	2
.L_SF:			.long	(P_MD_PCB)
.L_cpu_switch_prepare:	.long	_C_LABEL(cpu_switch_prepare)
FUNC_SYMBOL(switch_resume)

#ifdef SH3
/*
 * LINTSTUB: Func: void sh3_switch_resume(struct proc *p)
 *	Set current u-area PTE array to curupte.
 *	No need to flush any entries. it is depended on u-area mapping is
 *	wired, and its mapping never cause modified/reference fault.
 *	u-area TLB fault is only covered by TLB miss exception.
 *	When the situation that "VPN match but not Valid" occur, SH3 jump to
 *	"generic exception" handler instead of TLB miss exception.
 *	But OpenBSD/sh code doesn't handle it. As the result, it causes
 *	hard reset. (never can access kernel stack).
 */
NENTRY(sh3_switch_resume)
	mov.l	.L_UPTE, r0
	mov.l	.L_curupte, r1
	add	r4,	r0	/* p->p_md.md_upte */
	rts
	 mov.l	r0,	@r1
	.align	2
.L_UPTE:		.long	P_MD_UPTE
.L_curupte:		.long	_C_LABEL(curupte)
	SET_ENTRY_SIZE(sh3_switch_resume)
#endif /* SH3 */

#ifdef SH4
/*
 * LINTSTUB: Func: void sh4_switch_resume(struct proc *p)
 *	Wire u-area. invalidate TLB entry for kernel stack to prevent
 *	TLB multiple hit.
 */
NENTRY(sh4_switch_resume)
	mov.l	.L_UPTE__sh4, r0
	add	r0,	r4	/* p->p_md.md_upte */
	mov	#UPAGES,r3
	mov	#1,	r2
	mov.l	@r4,	r0	/* if (p->p_md.md_upte[0].addr == 0) return; */
	tst	r0,	r0
	bt	2f

	/* Save old ASID and set ASID to zero */
	xor	r0,	r0
	mov.l	.L_4_PTEH, r1
	mov.l	@r1,	r7
	mov.l	r0,	@r1

	mov.l	.L_VPN_MASK, r6
	mov.l	.L_4_UTLB_AA_A, r5

	/* TLB address array must be accessed via P2. Setup jump address. */
	mova	1f,	r0
	mov.l	.L_P2BASE, r1
	or	r1,	r0
	jmp	@r0		/* run P2 */
	 nop

	/* Probe VPN match TLB entry and invalidate it. */
	.align	2		/* mova target must be 4byte alignment */
1:	mov.l	@(4, r4), r0
	and	r6,	r0
	mov.l	r0,	@r5	/* clear D, V */

	/* Wire u-area TLB entry */
	/* Address array */
	mov.l	@r4+,	r0	/* addr */
	mov.l	@r4+,	r1	/* data */
	mov.l	r1,	@r0	/* *addr = data */

	/* Data array */
	mov.l	@r4+,	r0	/* addr */
	mov.l	@r4+,	r1	/* data */
	mov.l	r1,	@r0	/* *addr = data */
	cmp/eq	r2,	r3
	bf/s	1b
	 add	#1,	r2

	/* restore ASID */
	mov.l	.L_4_PTEH, r0
	mov.l	r7,	@r0
	mova	2f,	r0
	jmp	@r0		/* run P1 */
	 nop
	.align	2
2:	rts			/* mova target must be 4byte alignment */
	 nop
	.align	2
.L_UPTE__sh4:		.long	P_MD_UPTE
.L_4_PTEH:		.long	SH4_PTEH
.L_4_UTLB_AA_A:		.long	(SH4_UTLB_AA | SH4_UTLB_A)
.L_4_ITLB_AA:		.long	SH4_ITLB_AA
.L_VPN_MASK:		.long	0xfffff000
.L_P2BASE:		.long	0xa0000000
	SET_ENTRY_SIZE(sh4_switch_resume)
#endif /* SH4 */

/*
 * LINTSTUB: Func: int _cpu_intr_raise(int s)
 *	raise SR.IMASK to 's'. if current SR.IMASK is greater equal 's',
 *	nothing to do. returns previous SR.IMASK.
 */
NENTRY(_cpu_intr_raise)
	stc	sr,	r2
	mov	#0x78,	r1
	mov	r2,	r0
	shll	r1		/* r1 = 0xf0 */
	and	r1,	r0	/* r0 = SR & 0xf0 */
	cmp/ge	r4,	r0	/* r0 >= r4 ? T = 1 */
	bt/s	1f
	 not	r1,	r1	/* r1 = 0xffffff0f */
	and	r1,	r2	/* r2 = SR & ~0xf0 */
	or	r2,	r4	/* r4 = (SR & ~0xf0) | s */
	ldc	r4,	sr	/* SR = r4 (don't move to delay slot) */
1:	rts
	 nop	/* return (SR & 0xf0) */
	SET_ENTRY_SIZE(_cpu_intr_raise)

/*
 * LINTSTUB: Func: int _cpu_intr_suspend(void)
 *	Mask all external interrupt. Returns previous SR.IMASK.
 */
NENTRY(_cpu_intr_suspend)
	stc	sr,	r0	/* r0 = SR */
	mov	#0x78,	r1
	shll	r1		/* r1 = 0x000000f0 */
	mov	r0,	r2	/* r2 = SR */
	or	r1,	r2	/* r2 |= 0x000000f0 */
	ldc	r2,	sr	/* SR = r2 */
	rts
	 and	r1,	r0	/* r0 = SR & 0x000000f0 */
	SET_ENTRY_SIZE(_cpu_intr_suspend)

/*
 * LINTSTUB: Func: int _cpu_intr_resume(int s)
 *	Set 's' to SR.IMASK. Returns previous SR.IMASK.
 */
NENTRY(_cpu_intr_resume)
	stc	sr,	r0	/* r0 = SR */
	mov	#0x78,	r2
	shll	r2		/* r2 = 0x000000f0 */
	not	r2,	r1	/* r1 = 0xffffff0f */
	and	r0,	r1	/* r1 = (SR & ~0xf0) */
	or	r1,	r4	/* r4 = (SR & ~0xf0) | level */
	ldc	r4,	sr	/* SR = r0 (don't move to delay slot) */
	rts
	 and	r2,	r0	/* return (SR & 0xf0) */
	SET_ENTRY_SIZE(_cpu_intr_resume)

/*
 * LINTSTUB: Func: int _cpu_exception_suspend(void)
 *	Block exception (SR.BL). if external interrupt raise, pending interrupt.
 *	if exception occur, jump to 0xa0000000 (hard reset).
 */
NENTRY(_cpu_exception_suspend)
	stc	sr,	r0	/* r0 = SR */
	mov	#0x10,	r1
	swap.b	r1,	r1
	mov	r0,	r2	/* r2 = r0 */
	swap.w	r1,	r1	/* r1 = 0x10000000 */
	or	r1,	r2	/* r2 |= 0x10000000 */
	ldc	r2,	sr	/* SR = r2 */
	rts
	 and	r1,	r0	/* r0 &= 0x10000000 */
	SET_ENTRY_SIZE(_cpu_exception_suspend)

/*
 * LINTSTUB: Func: void _cpu_exception_resume(int s)
 *	restore 's' exception mask. (SR.BL)
 */
NENTRY(_cpu_exception_resume)
	stc	sr,	r0	/* r0 = SR */
	mov	#0x10,	r1
	swap.b	r1,	r1
	swap.w	r1,	r1
	not	r1,	r1	/* r1 = ~0x10000000 */
	and	r1,	r0	/* r0 &= ~0x10000000 */
	or	r4,	r0	/* r0 |= old SR.BL */
	ldc	r0,	sr	/* SR = r0 (don't move to delay slot) */
	rts
	 nop
	SET_ENTRY_SIZE(_cpu_exception_resume)

/*
 * LINTSTUB: Func: void _cpu_spin(uint32_t count)
 *	Loop for 'count' * 10 cycles.
 * [...]
 * add    IF ID EX MA WB
 * nop       IF ID EX MA WB
 * cmp/pl       IF ID EX MA WB -  -
 * nop             IF ID EX MA -  -  WB
 * bt                 IF ID EX .  .  MA WB
 * nop                   IF ID -  -  EX MA WB
 * nop                      IF -  -  ID EX MA WB
 * nop                      -  -  -  IF ID EX MA WB
 * add                                  IF ID EX MA WB
 * nop                                     IF ID EX MA WB
 * cmp/pl                                     IF ID EX MA WB -  -
 * nop                                           IF ID EX MA -  - WB
 * bt                                               IF ID EX .  . MA
 * [...]
 */
	.align 5	/* align cache line size (32B) */
NENTRY(_cpu_spin)
1:	nop			/* 1 */
	nop			/* 2 */
	nop			/* 3 */
	add	#-1, r4		/* 4 */
	nop			/* 5 */
	cmp/pl	r4		/* 6 */
	nop			/* 7 */
	bt	1b		/* 8, 9, 10 */
	rts
	 nop
	SET_ENTRY_SIZE(_cpu_spin)

/*
 * proc_trapmpoline:
 *	Call the service function with one argument specified by the r12 and r11
 *	respectively. set by cpu_fork().
 */
NENTRY(proc_trampoline)
	jsr	@r12
	 mov	r11,	r4
	__EXCEPTION_RETURN
	/* NOTREACHED */
	SET_ENTRY_SIZE(proc_trampoline)

/*
 * LINTSTUB: Var: char sigcode[1]
 *	Signal trampoline.
 *
 *	The kernel arranges for the signal handler to be invoked directly.
 *	This trampoline is used only to perform the return.
 *
 *	On entry, the stack looks like this:
 *
 *	sp->	sigcontext structure
 */
NENTRY(sigcode)
	mov	r15, r4			/* get pointer to sigcontext */
	mov.l	.L_SYS_sigreturn, r0
	trapa	#0x80			/* and call sigreturn() */
	mov.l	.L_SYS_exit, r0
	trapa	#0x80			/* exit if sigreturn fails */
	/* NOTREACHED */

	.align	2
.L_SYS_sigreturn:	.long	SYS_sigreturn
.L_SYS_exit:		.long	SYS_exit

/* LINTSTUB: Var: char esigcode[1] */
.globl	_C_LABEL(esigcode)
_C_LABEL(esigcode):
	SET_ENTRY_SIZE(sigcode)

/*
 * LINTSTUB: Func: void savectx(struct pcb *pcb)
 *	save struct switchframe.
 */
ENTRY(savectx)
	SAVEPCB(r4)
	add	#PCB_FP, r4
	SAVEFP(r4, r0, r1)
	rts
	 nop
	SET_ENTRY_SIZE(savectx)

/*
 * void fpu_save(struct fpreg *fp)
 *
 * Saves fpu context.
 */
ENTRY(fpu_save)
	SAVEFP(r4, r0, r1)
	rts
	 nop
	SET_ENTRY_SIZE(fpu_save)

/*
 * void fpu_restore(struct fpreg *fp)
 *
 * Restores fpu context.
 */
ENTRY(fpu_restore)
	LOADFP(r4, r0)
	rts
	 nop
	SET_ENTRY_SIZE(fpu_restore)

/*
 * LINTSTUB: Func: int copyout(const void *ksrc, void *udst, size_t len)
 *	Copy len bytes into the user address space.
 */
ENTRY(copyout)
	mov.l	r14,	@-r15
	sts.l	pr,	@-r15
	mov	r15,	r14

	mov	#EFAULT, r0		/* assume there was a problem */
	mov	r4,	r3
	mov	r5,	r2
	mov	r5,	r4
	add	r6,	r2
	cmp/hs	r5,	r2		/* bomb if uaddr+len wraps */
	bf	2f
	mov.l	.L_copyout_VM_MAXUSER_ADDRESS, r1
	cmp/hi	r1,	r2		/* bomb if uaddr isn't in user space */
	bt	2f

	mov.l	.L_copyout_curpcb, r1	/* set fault handler */
	mov.l	@r1,	r2
	mov.l	.L_copyout_onfault, r1
	mov.l	r1,	@(PCB_ONFAULT,r2)
	mov.l	.L_copyout_memcpy, r1
	jsr	@r1			/* memcpy(uaddr, kaddr, len) */
	 mov	r3,	r5

	mov	#0,	r0
1:
	mov.l	.L_copyout_curpcb, r1	/* clear fault handler */
	mov.l	@r1,	r2
	mov	#0,	r1
	mov.l	r1,	@(PCB_ONFAULT,r2)
2:
	mov	r14,	r15
	lds.l	@r15+,	pr
	rts
	 mov.l	@r15+,	r14

3:
	bra	1b
	 mov	#EFAULT, r0

	.align 2
.L_copyout_onfault:
	.long	3b
.L_copyout_VM_MAXUSER_ADDRESS:
	.long	VM_MAXUSER_ADDRESS
.L_copyout_curpcb:
	.long	_C_LABEL(curpcb)
.L_copyout_memcpy:
	.long	_C_LABEL(memcpy)
	SET_ENTRY_SIZE(copyout)

/*
 * LINTSTUB: Func: int copyin(const void *usrc, void *kdst, size_t len)
 *	Copy len bytes from the user address space.
 */
ENTRY(copyin)
	mov.l	r14,	@-r15
	sts.l	pr,	@-r15
	mov	r15,	r14

	mov	#EFAULT, r0		/* assume there was a problem */
	mov	r4,	r3
	mov	r5,	r4
	mov	r3,	r2
	add	r6,	r2
	cmp/hs	r3,	r2		/* bomb if uaddr+len wraps */
	bf	2f
	mov.l	.L_copyin_VM_MAXUSER_ADDRESS, r1
	cmp/hi	r1,	r2		/* bomb if uaddr isn't in user space */
	bt	2f

	mov.l	.L_copyin_curpcb, r1	/* set fault handler */
	mov.l	@r1,	r2
	mov.l	.L_copyin_onfault, r1
	mov.l	r1,	@(PCB_ONFAULT,r2)
	mov.l	.L_copyin_memcpy, r1
	jsr	@r1			/* memcpy(kaddr, uaddr, len) */
	 mov	r3,	r5

	mov	#0,	r0
1:
	mov.l	.L_copyin_curpcb, r1	/* clear fault handler */
	mov.l	@r1,	r2
	mov	#0,	r1
	mov.l	r1,	@(PCB_ONFAULT,r2)
2:
	mov	r14,	r15
	lds.l	@r15+,	pr
	rts
	 mov.l	@r15+,	r14

3:
	bra	1b
	 mov	#EFAULT, r0

	.align 2
.L_copyin_onfault:
	.long	3b
.L_copyin_VM_MAXUSER_ADDRESS:
	.long	VM_MAXUSER_ADDRESS
.L_copyin_curpcb:
	.long	_C_LABEL(curpcb)
.L_copyin_memcpy:
	.long	_C_LABEL(memcpy)
	SET_ENTRY_SIZE(copyin)

/*
 * LINTSTUB: Func: int copyoutstr(const void *ksrc, void *udst, size_t maxlen, size_t *lencopied)
 *	Copy a NUL-terminated string, at most maxlen characters long,
 *	into the user address space.  Return the number of characters
 *	copied (including the NUL) in *lencopied.  If the string is
 *	too long, return ENAMETOOLONG; else return 0 or EFAULT.
 */
ENTRY(copyoutstr)
	mov.l	r8,	@-r15

	mov	#EFAULT, r3		/* assume there was a problem */
	mov	r4,	r8
	mov.l	.L_copyoutstr_curpcb, r1	/* set fault handler */
	mov.l	@r1,	r2
	mov.l	.L_copyoutstr_onfault, r1
	mov.l	r1,	@(PCB_ONFAULT,r2)
	mov.l	.L_copyoutstr_VM_MAXUSER_ADDRESS, r1
	cmp/hi	r1,	r5		/* bomb if udst isn't in user space */
	bt	4f
	mov	r1,	r0
	sub	r5,	r0
	cmp/hi	r6,	r0		/* don't beyond user space */
	bf	2f
	bra	2f
	 mov	r6,	r0

	.align 2
1:
	mov.b	@r4+,	r1		/* copy str */
	mov.b	r1,	@r5
	extu.b	r1,	r1
	add	#1,	r5
	tst	r1,	r1
	bf	2f
	bra	3f
	 mov	#0,	r3
	.align 2
2:
	add	#-1,	r0
	cmp/eq	#-1,	r0
	bf	1b
	mov.l	.L_copyoutstr_VM_MAXUSER_ADDRESS, r1
	cmp/hs	r1,	r5
	bt	3f
	mov	#ENAMETOOLONG, r3

3:
	tst	r7,	r7		/* set lencopied if needed */
	bt	4f
	mov	r4,	r1
	sub	r8,	r1
	mov.l	r1,	@r7
4:
	mov.l	.L_copyoutstr_curpcb, r1	/* clear fault handler */
	mov.l	@r1,	r2
	mov	#0,	r1
	mov.l	r1,	@(PCB_ONFAULT,r2)

	mov	r3,	r0
	rts
	 mov.l	@r15+,	r8

5:
	bra	4b
	 mov	#EFAULT, r3

	.align 2
.L_copyoutstr_onfault:
	.long	5b
.L_copyoutstr_VM_MAXUSER_ADDRESS:
	.long	VM_MAXUSER_ADDRESS
.L_copyoutstr_curpcb:
	.long	_C_LABEL(curpcb)
	SET_ENTRY_SIZE(copyoutstr)

/*
 * LINTSTUB: Func: int copyinstr(const void *src, void *dst, size_t maxlen, size_t *lencopied)
 *	Copy a NUL-terminated string, at most maxlen characters long,
 *	from the user address space.  Return the number of characters
 *	copied (including the NUL) in *lencopied.  If the string is
 *	too long, return ENAMETOOLONG; else return 0 or EFAULT.
 */
ENTRY(copyinstr)
	mov.l	r8,	@-r15
	mov	#EFAULT, r3		/* assume there was a problem */
	mov	r4,	r8
	mov.l	.L_copyinstr_curpcb, r1	/* set fault handler */
	mov.l	@r1,	r2
	mov.l	.L_copyinstr_onfault, r1
	mov.l	r1,	@(PCB_ONFAULT,r2)

	mov.l	.L_copyinstr_VM_MAXUSER_ADDRESS, r1
	cmp/hi	r1,	r4		/* bomb if src isn't in user space */
	bt	4f
	mov	r1,	r0
	sub	r4,	r0
	cmp/hi	r6,	r0		/* don't beyond user space */
	bf	2f
	bra	2f
	 mov	r6,	r0

	.align 2
1:
	mov.b	@r4+,	r1		/* copy str */
	mov.b	r1,	@r5
	extu.b	r1,	r1
	add	#1,	r5
	tst	r1,	r1
	bf	2f
	bra	3f
	 mov	#0,	r3
	.align 2
2:
	add	#-1,	r0
	cmp/eq	#-1,	r0
	bf	1b
	mov.l	.L_copyinstr_VM_MAXUSER_ADDRESS, r1
	cmp/hs	r1,	r4
	bt	3f
	mov	#ENAMETOOLONG, r3

3:
	tst	r7,	r7		/* set lencopied if needed */
	bt	4f
	mov	r4,	r1
	sub	r8,	r1
	mov.l	r1,	@r7
4:
	mov.l	.L_copyinstr_curpcb, r1	/* clear fault handler */
	mov.l	@r1,	r2
	mov	#0,	r1
	mov.l	r1,	@(PCB_ONFAULT,r2)

	mov	r3,	r0
	rts
	 mov.l	@r15+,	r8

5:
	bra	4b
	 mov	#EFAULT, r3

	.align 2
.L_copyinstr_onfault:
	.long	5b
.L_copyinstr_VM_MAXUSER_ADDRESS:
	.long	VM_MAXUSER_ADDRESS
.L_copyinstr_curpcb:
	.long	_C_LABEL(curpcb)
	SET_ENTRY_SIZE(copyinstr)

/*
 * LINTSTUB: Func: int kcopy(const void *src, void *dst, size_t len)
 */
ENTRY(kcopy)
	mov.l	r8,	@-r15
	mov.l	r14,	@-r15
	sts.l	pr,	@-r15
	mov	r15,	r14

	mov	r4,	r3
	mov.l	.L_kcopy_curpcb, r1
	mov.l	@r1,	r2
	mov.l	@(PCB_ONFAULT,r2) ,r8	/* save old fault handler */
	mov.l	.L_kcopy_onfault, r1
	mov.l	r1,	@(PCB_ONFAULT,r2) /* set fault handler */
	mov.l	.L_kcopy_memcpy, r1
	mov	r5,	r4
	jsr	@r1			/* memcpy(dst, src, len) */
	 mov	r3,	r5
	mov	#0,	r0
1:
	mov.l	.L_kcopy_curpcb, r1	/* restore fault handler */
	mov.l	@r1,	r2
	mov.l	r8,	@(PCB_ONFAULT,r2)

	mov	r14,	r15
	lds.l	@r15+,	pr
	mov.l	@r15+,	r14
	rts
	 mov.l	@r15+,	r8

2:
	bra	1b
	 mov	#EFAULT, r0

	.align 2
.L_kcopy_onfault:
	.long	2b
.L_kcopy_curpcb:
	.long	_C_LABEL(curpcb)
.L_kcopy_memcpy:
	.long	_C_LABEL(memcpy)
	SET_ENTRY_SIZE(kcopy)

#if defined(DDB)

/*
 * LINTSTUB: Func: int setjmp(label_t *jmpbuf)
 */
ENTRY(setjmp)
	add	#4*9,	r4
	mov.l	r8,	@-r4
	mov.l	r9,	@-r4
	mov.l	r10,	@-r4
	mov.l	r11,	@-r4
	mov.l	r12,	@-r4
	mov.l	r13,	@-r4
	mov.l	r14,	@-r4
	mov.l	r15,	@-r4
	sts.l	pr,	@-r4
	rts
	 xor	r0, r0
	SET_ENTRY_SIZE(setjmp)

/*
 * LINTSTUB: Func: void longjmp(label_t *jmpbuf)
 */
ENTRY(longjmp)
	lds.l	@r4+,	pr
	mov.l	@r4+,	r15
	mov.l	@r4+,	r14
	mov.l	@r4+,	r13
	mov.l	@r4+,	r12
	mov.l	@r4+,	r11
	mov.l	@r4+,	r10
	mov.l	@r4+,	r9
	mov.l	@r4+,	r8
	rts
	 mov	#1, r0		/* return 1 from setjmp */
	SET_ENTRY_SIZE(longjmp)

#endif /* DDB */


code:
/*	$OpenBSD: mem.c,v 1.6 2015/02/10 22:44:35 miod Exp $	*/
/*	$NetBSD: mem.c,v 1.21 2006/07/23 22:06:07 ad Exp $	*/

/*
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 * Copyright (c) 1982, 1986, 1990, 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
 * Science Department.
 *
 * 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.
 *
 *	@(#)mem.c	8.3 (Berkeley) 1/12/94
 */

/*
 * Copyright (c) 1988 University of Utah.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * 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 by the University of
 *	California, Berkeley and its contributors.
 * 4. 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.
 *
 *	@(#)mem.c	8.3 (Berkeley) 1/12/94
 */

/*
 * Memory special file
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/conf.h>

#include <uvm/uvm_extern.h>

caddr_t zeropage;
boolean_t __mm_mem_addr(paddr_t);

#define mmread	mmrw
#define mmwrite	mmrw
cdev_decl(mm);

#define	DEV_MEM		0
#define	DEV_KMEM	1
#define	DEV_NULL	2
#define	DEV_ZERO	12

/* ARGSUSED */
int
mmopen(dev_t dev, int flag, int mode, struct proc *p)
{
	switch (minor(dev)) {
	case DEV_MEM:
	case DEV_KMEM:
	case DEV_NULL:
	case DEV_ZERO:
		break;
	default:
		return (ENXIO);
	}

	return (0);
}

/*ARGSUSED*/
int
mmclose(dev_t dev, int flag, int mode, struct proc *p)
{
	return (0);
}

/*ARGSUSED*/
int
mmrw(dev_t dev, struct uio *uio, int flags)
{
	struct iovec *iov;
	vaddr_t v, o;
	size_t c;
	int error = 0;

	while (uio->uio_resid > 0 && !error) {
		iov = uio->uio_iov;
		if (iov->iov_len == 0) {
			uio->uio_iov++;
			uio->uio_iovcnt--;
			if (uio->uio_iovcnt < 0)
				panic("mmrw");
			continue;
		}

		v = uio->uio_offset;

		switch (minor(dev)) {
		case DEV_MEM:
			/* Physical address */
			if (__mm_mem_addr(v)) {
				o = v & PGOFSET;
				c = ulmin(uio->uio_resid, PAGE_SIZE - o);
				error = uiomove((caddr_t)SH3_PHYS_TO_P1SEG(v),
				    c, uio);
			} else {
				return (EFAULT);
			}
			break;

		case DEV_KMEM:
			if (v < SH3_P1SEG_BASE)			/* P0 */
				return (EFAULT);
			if (v < SH3_P2SEG_BASE) {		/* P1 */
				/* permitted */
			/*
				if (__mm_mem_addr(SH3_P1SEG_TO_PHYS(v))
				    == FALSE)
					return (EFAULT);
			*/
				c = ulmin(iov->iov_len, MAXPHYS);
				error = uiomove((caddr_t)v, c, uio);
			} else if (v < SH3_P3SEG_BASE)		/* P2 */
				return (EFAULT);
			else {					/* P3 */
				c = ulmin(iov->iov_len, MAXPHYS);
				if (!uvm_kernacc((void *)v, c,
				    uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
					return (EFAULT);
				error = uiomove((caddr_t)v, c, uio);
			}
			break;

		case DEV_NULL:
			if (uio->uio_rw == UIO_WRITE)
				uio->uio_resid = 0;
			return (0);

		case DEV_ZERO:
			if (uio->uio_rw == UIO_WRITE) {
				uio->uio_resid = 0;
				return (0);
			}
			if (zeropage == NULL)
				zeropage = malloc(PAGE_SIZE, M_TEMP,
				    M_WAITOK | M_ZERO);
			c = ulmin(iov->iov_len, PAGE_SIZE);
			error = uiomove(zeropage, c, uio);
			break;

		default:
			return (ENXIO);
		}
	}

	return (error);
}

/*ARGSUSED*/
paddr_t
mmmmap(dev_t dev, off_t off, int prot)
{
	struct proc *p = curproc;

	if (minor(dev) != DEV_MEM)
		return (-1);

	if (__mm_mem_addr((paddr_t)off) == FALSE && suser(p, 0) != 0)
		return (-1);
	return ((paddr_t)off);
}

/*ARGSUSED*/
int
mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	return (EOPNOTSUPP);
}

/*
 * boolean_t __mm_mem_addr(paddr_t pa):
 *	Check specified physical address is in physical memory, with the
 *	kernel image off-limits.
 */
boolean_t
__mm_mem_addr(paddr_t pa)
{
#if 0
	extern vaddr_t kernend; /* from machdep.c */
#endif
	struct vm_physseg *seg;
	unsigned int segno;

	for (segno = 0, seg = vm_physmem; segno < vm_nphysseg; segno++, seg++) {
		if (pa < seg->start || pa >= seg->end)
			continue;

#if 0
		/*
		 * This assumes the kernel image occupies the beginning of a
		 * memory segment.
		 */
		if (kernend >= seg->start && kernend < seg->end) {
			if (pa < kernend)
				return (FALSE);
		}
#endif

		return (TRUE);
	}

	return (FALSE);
}


code:
/*	$OpenBSD: mmu.c,v 1.4 2010/06/02 05:35:17 jasper Exp $	*/
/*	$NetBSD: mmu.c,v 1.15 2006/02/12 02:30:55 uwe Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * 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.
 */

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

#include <sh/mmu.h>
#include <sh/mmu_sh3.h>
#include <sh/mmu_sh4.h>

#if defined(SH3) && defined(SH4)
void (*__sh_mmu_start)(void);
void (*__sh_tlb_invalidate_addr)(int, vaddr_t);
void (*__sh_tlb_invalidate_asid)(int);
void (*__sh_tlb_invalidate_all)(void);
void (*__sh_tlb_update)(int, vaddr_t, uint32_t);
#endif /* SH3 && SH4 */

void
sh_mmu_init(void)
{
	/*
	 * Assign function hooks but only if both SH3 and SH4 are defined.
	 * They are called directly otherwise.  See <sh3/mmu.h>.
	 */
#if defined(SH3) && defined(SH4)
	if (CPU_IS_SH3) {
		__sh_mmu_start = sh3_mmu_start;
		__sh_tlb_invalidate_addr = sh3_tlb_invalidate_addr;
		__sh_tlb_invalidate_asid = sh3_tlb_invalidate_asid;
		__sh_tlb_invalidate_all = sh3_tlb_invalidate_all;
		__sh_tlb_update = sh3_tlb_update;
	}
	else if (CPU_IS_SH4) {
		__sh_mmu_start = sh4_mmu_start;
		__sh_tlb_invalidate_addr = sh4_tlb_invalidate_addr;
		__sh_tlb_invalidate_asid = sh4_tlb_invalidate_asid;
		__sh_tlb_invalidate_all = sh4_tlb_invalidate_all;
		__sh_tlb_update = sh4_tlb_update;
	}
#endif /* SH3 && SH4 */
}

void
sh_mmu_information(void)
{
#ifdef DEBUG
	uint32_t r;
#ifdef SH3
	if (CPU_IS_SH3) {
		printf("cpu0: 4-way set-associative 128 TLB entries\n");
		r = _reg_read_4(SH3_MMUCR);
		printf("cpu0: %s mode, %s virtual storage mode\n",
		    r & SH3_MMUCR_IX ? "ASID+VPN" : "VPN",
		    r & SH3_MMUCR_SV ? "single" : "multiple");
	}
#endif
#ifdef SH4
	if (CPU_IS_SH4) {
		unsigned int urb;
		printf("cpu0: fully-associative 4 ITLB, 64 UTLB entries\n");
		r = _reg_read_4(SH4_MMUCR);
		urb = (r & SH4_MMUCR_URB_MASK) >> SH4_MMUCR_URB_SHIFT;
		printf("cpu0: %s virtual storage mode, SQ access: kernel%s, ",
		    r & SH3_MMUCR_SV ? "single" : "multiple",
		    r & SH4_MMUCR_SQMD ? "" : "/user");
		printf("wired %d\n",
		    urb ? 64 - urb : 0);
	}
#endif
#endif /* DEBUG */
}

void
sh_tlb_set_asid(int asid)
{
	_reg_write_4(SH_(PTEH), asid);
}


code:
/*	$OpenBSD: mmu_sh3.c,v 1.2 2008/06/26 05:42:13 ray Exp $	*/
/*	$NetBSD: mmu_sh3.c,v 1.11 2006/03/04 01:13:35 uwe Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * 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.
 */

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

#include <sh/pte.h>	/* OpenBSD/sh specific PTE */
#include <sh/mmu.h>
#include <sh/mmu_sh3.h>

void
sh3_mmu_start()
{
	/* Zero clear all TLB entry */
	sh3_tlb_invalidate_all();

	/* Set current ASID to 0 */
	sh_tlb_set_asid(0);

	_reg_write_4(SH3_MMUCR, SH3_MMUCR_AT | SH3_MMUCR_TF);
}

void
sh3_tlb_invalidate_addr(int asid, vaddr_t va)
{
	uint32_t a, d;
	int w;

	d = (va & SH3_MMUAA_D_VPN_MASK_4K) | asid;  /* 4K page */
	va = va & SH3_MMU_VPN_MASK;   /* [16:12] entry index */

	/* Probe entry and invalidate it. */
	for (w = 0; w < SH3_MMU_WAY; w++) {
		a = va | (w << SH3_MMU_WAY_SHIFT); /* way [9:8] */
		if ((_reg_read_4(SH3_MMUAA | a) &
		    (SH3_MMUAA_D_VPN_MASK_4K | SH3_MMUAA_D_ASID_MASK)) == d) {
			_reg_write_4(SH3_MMUAA | a, 0);
			break;
		}
	}
}

void
sh3_tlb_invalidate_asid(int asid)
{
	uint32_t aw, a;
	int e, w;

	/* Invalidate entry attribute to ASID */
	for (w = 0; w < SH3_MMU_WAY; w++) {
		aw = (w << SH3_MMU_WAY_SHIFT);
		for (e = 0; e < SH3_MMU_ENTRY; e++) {
			a = aw | (e << SH3_MMU_VPN_SHIFT);
			if ((_reg_read_4(SH3_MMUAA | a) &
			    SH3_MMUAA_D_ASID_MASK) == asid) {
				_reg_write_4(SH3_MMUAA | a, 0);
			}
		}
	}
}

void
sh3_tlb_invalidate_all()
{
	uint32_t aw, a;
	int e, w;

	/* Zero clear all TLB entry to avoid unexpected VPN match. */
	for (w = 0; w < SH3_MMU_WAY; w++) {
		aw = (w << SH3_MMU_WAY_SHIFT);
		for (e = 0; e < SH3_MMU_ENTRY; e++) {
			a = aw | (e << SH3_MMU_VPN_SHIFT);
			_reg_write_4(SH3_MMUAA | a, 0);
			_reg_write_4(SH3_MMUDA | a, 0);
		}
	}
}

void
sh3_tlb_update(int asid, vaddr_t va, uint32_t pte)
{
	uint32_t oasid;

	KDASSERT(asid < 0x100 && (pte & ~PGOFSET) != 0 && va != 0);

	/* Save old ASID */
	oasid = _reg_read_4(SH3_PTEH) & SH3_PTEH_ASID_MASK;

	/* Invalidate old entry (if any) */
	sh3_tlb_invalidate_addr(asid, va);

	/* Load new entry */
	_reg_write_4(SH3_PTEH, (va & ~PGOFSET) | asid);
	_reg_write_4(SH3_PTEL, pte & PG_HW_BITS);
	__asm volatile("ldtlb");

	/* Restore old ASID */
	if (asid != oasid)
		_reg_write_4(SH3_PTEH, oasid);
}


code:
/*	$OpenBSD: mmu_sh4.c,v 1.2 2008/06/26 05:42:13 ray Exp $	*/
/*	$NetBSD: mmu_sh4.c,v 1.11 2006/03/04 01:13:35 uwe Exp $	*/

/*-
 * Copyright (c) 2002 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by UCHIYAMA Yasushi.
 *
 * 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.
 */

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

#include <sh/pte.h>	/* OpenBSD/sh specific PTE */
#include <sh/mmu.h>
#include <sh/mmu_sh4.h>

#define	SH4_MMU_HAZARD	__asm volatile("nop;nop;nop;nop;nop;nop;nop;nop;")

static inline void __sh4_itlb_invalidate_all(void);

static inline void
__sh4_itlb_invalidate_all()
{
	_reg_write_4(SH4_ITLB_AA, 0);
	_reg_write_4(SH4_ITLB_AA | (1 << SH4_ITLB_E_SHIFT), 0);
	_reg_write_4(SH4_ITLB_AA | (2 << SH4_ITLB_E_SHIFT), 0);
	_reg_write_4(SH4_ITLB_AA | (3 << SH4_ITLB_E_SHIFT), 0);
}

void
sh4_mmu_start()
{
	/* Zero clear all TLB entry */
	_reg_write_4(SH4_MMUCR, 0);	/* zero wired entry */
	sh_tlb_invalidate_all();

	/* Set current ASID to 0 */
	sh_tlb_set_asid(0);

	/*
	 * User can't access store queue
	 * make wired entry for u-area.
	 */
	_reg_write_4(SH4_MMUCR, SH4_MMUCR_AT | SH4_MMUCR_TI | SH4_MMUCR_SQMD |
	    (SH4_UTLB_ENTRY - UPAGES) << SH4_MMUCR_URB_SHIFT);

	SH4_MMU_HAZARD;
}

void
sh4_tlb_invalidate_addr(int asid, vaddr_t va)
{
	uint32_t pteh;
	int s;

	va &= SH4_PTEH_VPN_MASK;
	s = _cpu_exception_suspend();

	/* Save current ASID */
	pteh = _reg_read_4(SH4_PTEH);
	/* Set ASID for associative write */
	_reg_write_4(SH4_PTEH, asid);

	/* Associative write(UTLB/ITLB). not required ITLB invalidate. */
	RUN_P2;
	_reg_write_4(SH4_UTLB_AA | SH4_UTLB_A, va); /* Clear D, V */
	RUN_P1;
	/* Restore ASID */
	_reg_write_4(SH4_PTEH, pteh);

	_cpu_exception_resume(s);
}

void
sh4_tlb_invalidate_asid(int asid)
{
	uint32_t a;
	int e, s;

	s = _cpu_exception_suspend();
	/* Invalidate entry attribute to ASID */
	RUN_P2;
	for (e = 0; e < SH4_UTLB_ENTRY; e++) {
		a = SH4_UTLB_AA | (e << SH4_UTLB_E_SHIFT);
		if ((_reg_read_4(a) & SH4_UTLB_AA_ASID_MASK) == asid)
			_reg_write_4(a, 0);
	}

	__sh4_itlb_invalidate_all();
	RUN_P1;
	_cpu_exception_resume(s);
}

void
sh4_tlb_invalidate_all()
{
	uint32_t a;
	int e, eend, s;

	s = _cpu_exception_suspend();
	/* If non-wired entry limit is zero, clear all entry. */
	a = _reg_read_4(SH4_MMUCR) & SH4_MMUCR_URB_MASK;
	eend = a ? (a >> SH4_MMUCR_URB_SHIFT) : SH4_UTLB_ENTRY;

	RUN_P2;
	for (e = 0; e < eend; e++) {
		a = SH4_UTLB_AA | (e << SH4_UTLB_E_SHIFT);
		_reg_write_4(a, 0);
		a = SH4_UTLB_DA1 | (e << SH4_UTLB_E_SHIFT);
		_reg_write_4(a, 0);
	}
	__sh4_itlb_invalidate_all();
	_reg_write_4(SH4_ITLB_DA1, 0);
	_reg_write_4(SH4_ITLB_DA1 | (1 << SH4_ITLB_E_SHIFT), 0);
	_reg_write_4(SH4_ITLB_DA1 | (2 << SH4_ITLB_E_SHIFT), 0);
	_reg_write_4(SH4_ITLB_DA1 | (3 << SH4_ITLB_E_SHIFT), 0);
	RUN_P1;
	_cpu_exception_resume(s);
}

void
sh4_tlb_update(int asid, vaddr_t va, uint32_t pte)
{
	uint32_t oasid;
	uint32_t ptel;
	int s;

	KDASSERT(asid < 0x100 && (pte & ~PGOFSET) != 0 && va != 0);

	s = _cpu_exception_suspend();
	/* Save old ASID */
	oasid = _reg_read_4(SH4_PTEH) & SH4_PTEH_ASID_MASK;

	/* Invalidate old entry (if any) */
	sh4_tlb_invalidate_addr(asid, va);

	_reg_write_4(SH4_PTEH, asid);
	/* Load new entry */
	_reg_write_4(SH4_PTEH, (va & ~PGOFSET) | asid);
	ptel = pte & PG_HW_BITS;
	if (pte & _PG_PCMCIA) {
		_reg_write_4(SH4_PTEA,
		    (pte >> _PG_PCMCIA_SHIFT) & SH4_PTEA_SA_MASK);
	} else {
		_reg_write_4(SH4_PTEA, 0);
	}
	_reg_write_4(SH4_PTEL, ptel);
	__asm volatile("ldtlb; nop");

	/* Restore old ASID */
	if (asid != oasid)
		_reg_write_4(SH4_PTEH, oasid);
	_cpu_exception_resume(s);
}