code:
/*	$OpenBSD: locore.S,v 1.17 2015/07/29 18:52:44 miod Exp $	*/
/*	$NetBSD: locore.S,v 1.2 1996/10/16 19:33:09 ws Exp $	*/

/*
 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
 * Copyright (C) 1995, 1996 TooLs GmbH.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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>

#include <machine/asm.h>
#include <machine/param.h>
#include <machine/pmap.h>
#include <machine/psl.h>
#include <machine/trap.h>

#define GET_CPUINFO(r)	mfsprg r,0

#define	INTSTK		(8*1024)	/* 8K interrupt stack */
#define	SPILLSTK	(1*1024)
#define	DDBSTK		(7*1024)

/*
 * Globals
 */
	.globl	_C_LABEL(esym),_C_LABEL(proc0paddr)
	.type	_C_LABEL(esym),@object
	.type	_C_LABEL(proc0paddr),@object
	.data
_C_LABEL(esym):		.long	0	/* end of symbol table */
_C_LABEL(proc0paddr):	.long	0	/* proc0 p_addr */

	.globl	_C_LABEL(fwargsave)
	.type	_C_LABEL(fwargsave),@object
_C_LABEL(fwargsave):	.long	0

	.globl	_C_LABEL(fwfdtsave)
	.type	_C_LABEL(fwfdtsave),@object
_C_LABEL(fwfdtsave):	.long	0

/*
 * Startup entry
 */
_ENTRY(_C_LABEL(kernel_text))
_ENTRY(_ASM_LABEL(start))
/* arguments to start
 * r1 - stack provided by firmware/bootloader
 * r3 - unused
 * r4 - unused
 * r5 - firmware pointer (NULL for PPC1bug)
 * r6 - arg list
 * r7 - length
 */
	.globl	start
	.type start,@function
start:
	/* make sure address translation is disabled */
	mfmsr	%r9
	li	%r8,PSL_DR|PSL_IR
	andc	%r9,%r9,%r8
	sync
	mtmsr	%r9
	isync

	lis	%r8, fwargsave@ha
	stw	%r29, fwargsave@l(%r8)

	lis	%r8, fwfdtsave@ha
	stw	%r3, fwfdtsave@l(%r8)

/* compute end of kernel memory */
	lis	%r8,_end@ha
	addi	%r8,%r8,_end@l
	cmpwi	%r4,0
	beq	1f
	li	%r6,0
1:
#if defined(DDB)
	cmpwi	%r6, 0
	beq	2f
	add	%r9,%r6,%r7
	lwz	%r9, -4(%r9)
	cmpwi   %r9,0
	beq	2f
	lis	%r8,_C_LABEL(esym)@ha
	stw	%r9,_C_LABEL(esym)@l(%r8)
	mr	%r8, %r9
2:
#endif
	li	%r9,PGOFSET
	add	%r8,%r8,%r9
	andc	%r8,%r8,%r9
	lis	%r9,_C_LABEL(cpu_info)@ha
	addi	%r9,%r9,_C_LABEL(cpu_info)@l
	mtsprg	0,%r9
	addi	%r8,%r8,INTSTK
	stw	%r8,CI_INTSTK(%r9)
	li	%r0,-1
	stw	%r0,CI_INTRDEPTH(%r9)
	addi	%r8,%r8,SPILLSTK+DDBSTK	/* leave room for spillstk and ddbstk */
	lis	%r9,_C_LABEL(proc0paddr)@ha
	stw	%r8,_C_LABEL(proc0paddr)@l(%r9)
	addi	%r1,%r8,USPACE-FRAMELEN	/* stackpointer for proc0 */
	mr	%r4,%r1			/* end of mem reserved for kernel */
	li	%r0,0
	stwu	%r0,-16(%r1)		/* end of stack chain */

	lis	%r3,start@ha
	addi	%r3,%r3,start@l
	mr	%r5,%r6			/* args string */

	bl	_C_LABEL(initppc)
	bl	_C_LABEL(main)

#ifdef MULTIPROCESSOR
_ENTRY(_C_LABEL(cpu_spinup_trampoline))
	lis	%r3,_C_LABEL(cpu_hatch_stack)@ha
	lwz	%r1,_C_LABEL(cpu_hatch_stack)@l(%r3)

	b	_C_LABEL(cpu_hatch)
	/* NOTREACHED */
#endif

_ENTRY(_C_LABEL(prom_printf))
	lis	%r11, fwargsave@ha
	lwz	%r11, fwargsave@l(%r11)
	lwz	%r11, 88(%r11)
	lwz	%r11, 20(%r11)
	mtctr	%r11
	bctr

/*
 * void cpu_switchto(struct proc *old, struct proc *new)
 * Switch from "old" proc to "new".
 */
_ENTRY(_C_LABEL(cpu_switchto_asm))
	mflr	%r0			/* save lr */
	stw	%r0,4(%r1)
	stwu	%r1,-16(%r1)
	stw	%r31,12(%r1)
	stw	%r30,8(%r1)

/*
 * r3 - old proc
 * r4 -	new proc
 * r5 - cpuinfo
 */
	GET_CPUINFO(%r5)

	li	%r31,SONPROC
	stb	%r31,P_STAT(%r4)

	or.	%r3,%r3,%r3		/* old process was exiting? */
	beq	switch_exited

	mfsr	%r10,PPC_USER_SR	/* save PPC_USER_SR for copyin/copyout*/
	mfcr	%r11			/* save cr */
	mr	%r12,%r2		/* save r2 */
	stwu	%r1,-SFRAMELEN(%r1)	/* still running on old stack */
	stmw	%r10,8(%r1)
	lwz	%r31,P_ADDR(%r3)
	stw	%r1,PCB_SP(%r31)	/* save SP */

switch_exited:
	/* disable interrupts while actually switching */
	mfmsr	%r30
	andi.	%r30,%r30,~PSL_EE@l
	mtmsr	%r30

	stw	%r4,CI_CURPROC(%r5)	/* record new process */

#ifdef MULTIPROCESSOR
	stw	%r5,P_CPU(%r4)
#endif

	lwz	%r31,P_ADDR(%r4)
	stw	%r31,CI_CURPCB(%r5)	/* indicate new pcb */

	lwz	%r6,PCB_PMR(%r31)

	/* save real pmap pointer for spill fill */
	stwu	%r6,CI_CURPM(%r5)
	stwcx.	%r6,%r0,%r5		/* clear possible reservation */

	addic.	%r6,%r6,64
	li	%r5,0

	lwz	%r1,PCB_SP(%r31)	/* get new procs SP */

	ori	%r30,%r30,PSL_EE	/* interrupts are okay again */
	mtmsr	%r30

	lmw	%r10,8(%r1)		/* get other regs */
	lwz	%r1,0(%r1)		/* get saved SP */
	mr	%r2,%r12		/* get saved r2 */
	mtcr	%r11			/* get saved cr */
	isync
	mtsr	PPC_USER_SR,%r10	/* get saved PPC_USER_SR */
	isync

	lwz	%r31,12(%r1)
	lwz	%r30,8(%r1)
	addi	%r1,%r1,16
	lwz	%r0,4(%r1)
	mtlr	%r0
	blr

_ENTRY(_C_LABEL(cpu_idle_enter))
	lis	%r4, _C_LABEL(ppc_cpuidle)@ha
	lwz	%r4, _C_LABEL(ppc_cpuidle)@l(%r4)
	cmpwi	%r4, 0
	beq	1f
	/* must disable external interrupts during idle queue checking */
	mfmsr	%r3
	andi.	%r3,%r3,~PSL_EE@l
	mtmsr	%r3
1:
	blr

_ENTRY(_C_LABEL(cpu_idle_cycle))
	lis	%r4, _C_LABEL(ppc_cpuidle)@ha
	lwz	%r4, _C_LABEL(ppc_cpuidle)@l(%r4)
	cmpwi	%r4, 0
	beq	idledone

	/*
	 * Interrupts were disabled in cpu_idle_enter, but must be
	 * enabled for sleeping, but before that indicate that we
	 * are entering sleep mode.
	 */
	GET_CPUINFO(%r4)
	lwz	%r6,CI_FLAGS(%r4)
	ori	%r6,%r6,CI_FLAGS_SLEEPING@l
	stw	%r6,CI_FLAGS(%r4)

	/* enable interrupts, required before setting POW */
	mfmsr	%r3
	ori	%r5,%r3,PSL_EE@l
	mtmsr	%r5
	oris	%r5, %r5, PSL_POW@h
	sync
	/* low power mode */
	mtmsr	%r5
	sync
	isync

	/*
	 * restore interrupts to disabled, so CI_FLAGS is only modified
	 * with interrupts disabled.
	 */
	mtmsr %r3
	isync

	/* clear CI_FLAGS_SLEEPING since sleeping is over */
	andi.	%r6,%r6,~CI_FLAGS_SLEEPING@l
	stw	%r6,CI_FLAGS(%r4)
idledone:
	blr

_ENTRY(_C_LABEL(cpu_idle_leave))
	lis	%r4, _C_LABEL(ppc_cpuidle)@ha
	lwz	%r4, _C_LABEL(ppc_cpuidle)@l(%r4)
	cmpwi	%r4, 0
	beq	1f
	/* enable interrupts disabled in cpu_idle_enter. */
	mfmsr	%r3
	ori	%r3,%r3,PSL_EE@l
	mtmsr	%r3
1:
	blr

/*
 * This code gets copied to all the trap vectors
 * except ISI/DSI, ALI, and the interrupts
 */
	.text
	.globl	_C_LABEL(trapcode),_C_LABEL(trapsize)
	.type	_C_LABEL(trapcode),@function
	.type	_C_LABEL(trapsize),@object
_C_LABEL(trapcode):
	mtsprg	1,%r1			/* save SP */
nop32_1s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_1e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_TEMPSAVE(%r1)	/* free r28-r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfsprg	%r1,1			/* restore SP */

	/* Test whether we already had PR set */
	mfsrr1	%r31
	mtcr	%r31
	bc	4,17,1f			/* branch if PSL_PR is clear */
	GET_CPUINFO(%r1)
	lwz	%r1,CI_CURPCB(%r1)
	addi	%r1,%r1,USPACE		/* stack is top of user struct */
1:
	bla	s_trap
_C_LABEL(trapsize) =	.-_C_LABEL(trapcode)

/*
 * For ALI: has to save DSISR and DAR
 */
	.globl	_C_LABEL(alitrap),_C_LABEL(alisize)
_C_LABEL(alitrap):
	mtsprg	1,%r1			/* save SP */
nop32_2s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_2e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_TEMPSAVE(%r1)	/* free r28-r31 */
	mfdar	%r30
	mfdsisr	%r31
	stmw	%r30,CI_TEMPSAVE+16(%r1)
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfsprg	%r1,1			/* restore SP */

	/* Test whether we already had PR set */
	mfsrr1	%r31
	mtcr	%r31
	bc	4,17,1f			/* branch if PSL_PR is clear */
	GET_CPUINFO(%r1)
	lwz	%r1,CI_CURPCB(%r1)
	addi	%r1,%r1,USPACE		/* stack is top of user struct */
1:
	bla	s_trap
_C_LABEL(alisize) =	.-_C_LABEL(alitrap)

/*
 * Similar to the above for DSI
 * Has to handle BAT spills
 * and standard pagetable spills
 */
	.globl	_C_LABEL(dsitrap),_C_LABEL(dsisize)
	.type	_C_LABEL(dsitrap),@function
	.type	_C_LABEL(dsisize),@object
_C_LABEL(dsitrap):
	mtsprg	1,%r1
	GET_CPUINFO(%r1)
	stmw	%r28,CI_DISISAVE(%r1)	/* free r28-r31 */
nop32_3s:
	mfmsr	%r28
	clrldi	%r28,%r28,1
	mtmsrd	%r28
nop32_3e:
	mfsprg	%r1,1
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	mtsprg	2,%r30			/* in SPRG2 */
	mfsrr1	%r31			/* test kernel mode */
nopbat_1s:
	mtcr	%r31
	bc	12,17,1f		/* branch if PSL_PR is set */
	mfdar	%r31			/* get fault address */
	rlwinm	%r31,%r31,7,25,28	/* get segment * 8 */
	addis	%r31,%r31,_C_LABEL(battable)@ha
	lwz	%r30,_C_LABEL(battable)@l(%r31)	/* get batu */
	mtcr	%r30
	bc	4,30,1f			/* branch if supervisor valid is false */
	lwz	%r31,_C_LABEL(battable)+4@l(%r31)	/* get batl */
/* We randomly use the highest two bat registers here */
	mftb	%r28
	andi.	%r28,%r28,1
	bne	2f
	mtdbatu	2,%r30
	mtdbatl	2,%r31
	b	3f
2:
	mtdbatu	3,%r30
	mtdbatl	3,%r31
3:
	mfsprg	%r30,2			/* restore XER */
	mtxer	%r30
	mtcr	%r29			/* restore CR */
	mtsprg	1,%r1
	GET_CPUINFO(%r1)
	lmw	%r28,CI_DISISAVE(%r1)	/* restore r28-r31 */
	mfsprg	1,%r1
	rfi				/* return to trapped code */
1:
nopbat_1e:
	mflr	%r28			/* save LR */
	bla	s_dsitrap
_C_LABEL(dsisize) =	.-_C_LABEL(dsitrap)

/*
 * Similar to the above for ISI
 */
	.globl	_C_LABEL(isitrap),_C_LABEL(isisize)
	.type	_C_LABEL(isitrap),@function
	.type	_C_LABEL(isisize),@object
_C_LABEL(isitrap):
	mtsprg	1,%r1                   /* save SP */
nop32_4s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_4e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_DISISAVE(%r1)	/* free r28-r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfsrr1	%r31			/* test kernel mode */
	mfsprg	%r1,1                   /* restore SP */
	bla	s_isitrap
_C_LABEL(isisize) =	.-_C_LABEL(isitrap)

/*
 * This one for the external interrupt handler.
 */
	.globl	_C_LABEL(extint),_C_LABEL(extsize)
	.type	_C_LABEL(extint),@function
	.type	_C_LABEL(extsize),@object
_C_LABEL(extint):
	mtsprg	1,%r1			/* save SP */
nop32_5s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_5e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_TEMPSAVE(%r1)	/* free r28-r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	lwz	%r31,CI_INTRDEPTH(%r1)	/* were we already running on intstk? */
	addic.	%r31,%r31,1
	stw	%r31,CI_INTRDEPTH(%r1)
	lwz	%r1,CI_INTSTK(%r1)	/* get interrupt stack */
	beq	1f
	mfsprg	%r1,1			/* yes, get old SP */
1:
	ba	extintr
_C_LABEL(extsize) =	.-_C_LABEL(extint)

/*
 * And this one for the decrementer interrupt handler.
 */
	.globl	_C_LABEL(decrint),_C_LABEL(decrsize)
	.type	_C_LABEL(decrint),@function
	.type	_C_LABEL(decrsize),@object
_C_LABEL(decrint):
	mtsprg	1,%r1			/* save SP */
nop32_6s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_6e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_TEMPSAVE(%r1)	/* free r28-r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	lwz	%r31,CI_INTRDEPTH(%r1)	/* were we already running on intstk? */
	addic.	%r31,%r31,1
	stw	%r31,CI_INTRDEPTH(%r1)
	lwz	%r1,CI_INTSTK(%r1)	/* get interrupt stack */
	beq	1f
	mfsprg	%r1,1			/* yes, get old SP */
1:
	ba	decrintr
_C_LABEL(decrsize) =	.-_C_LABEL(decrint)

/*
 * Now the tlb software load for 603 processors:
 * (Code essentially from the 603e User Manual, Chapter 5)
 */
#define	DMISS	976
#define	DCMP	977
#define	HASH1	978
#define	HASH2	979
#define	IMISS	980
#define	ICMP	981
#define	RPA	982

#define	bdneq	bdnzf 2,
#define	tlbli	.long	0x7c0007e4+0x800*
#define	tlbld	.long	0x7c0007a4+0x800*

	.globl	_C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
	.type	_C_LABEL(tlbimiss),@function
	.type	_C_LABEL(tlbimsize),@object
_C_LABEL(tlbimiss):
	mfspr	%r2,HASH1		/* get first pointer */
	li	%r1,8
	mfctr	%r0			/* save counter */
	mfspr	%r3,ICMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	lwzu	%r1,8(%r2)		/* get next pte */
	cmpl	0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	lwz	%r1,4(%r2)		/* load tlb entry lower word */
	andi.	%r3,%r1,8		/* check G-bit */
	bne	4f			/* if guarded, take ISI */
	mtctr	%r0			/* restore counter */
	mfspr	%r0,IMISS		/* get the miss address for the tlbli */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	ori	%r1,%r1,0x100		/* set the reference bit */
	mtspr	RPA,%r1			/* set the pte */
	srwi	%r1,%r1,8		/* get byte 7 of pte */
	tlbli	0			/* load the itlb */
	stb	%r1,6(%r2)		/* update page table */
	rfi

3:	/* not found in pteg */
	andi.	%r1,%r3,0x40		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,HASH2		/* get the second pointer */
	ori	%r3,%r3,0x40		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
4:	/* guarded */
	mfsrr1	%r3
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	addis	%r2,%r2,0x800		/* set srr<4> to flag prot violation */
	b	6f
5:	/* not found anywhere */
	mfsrr1	%r3
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	addis	%r2,%r2,0x4000		/* set srr1<1> to flag pte not found */
6:
	mtctr	%r0			/* restore counter */
	mtsrr1	%r2
	mfmsr	%r0
	xoris	%r0,%r0,2		/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
	ba	EXC_ISI
_C_LABEL(tlbimsize) =	.-_C_LABEL(tlbimiss)

	.globl	_C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
	.type	_C_LABEL(tlbdlmiss),@function
	.type	_C_LABEL(tlbdlmsize),@object
_C_LABEL(tlbdlmiss):
	mfspr	%r2,HASH1		/* get first pointer */
	li	%r1,8
	mfctr	%r0			/* save counter */
	mfspr	%r3,DCMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	lwzu	%r1,8(%r2)		/* get next pte */
	cmpl	0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	lwz	%r1,4(%r2)		/* load tlb entry lower word */
	mtctr	%r0			/* restore counter */
	mfspr	%r0,DMISS		/* get the miss address for the tlbld */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	ori	%r1,%r1,0x100		/* set the reference bit */
	mtspr	RPA,%r1			/* set the pte */
	srwi	%r1,%r1,8		/* get byte 7 of pte */
	tlbld	0			/* load the dtlb */
	stb	%r1,6(%r2)		/* update page table */
	rfi

3:	/* not found in pteg */
	andi.	%r1,%r3,0x40		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,HASH2		/* get the second pointer */
	ori	%r3,%r3,0x40		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
5:	/* not found anywhere */
	mfsrr1	%r3
	lis	%r1,0x4000		/* set dsisr<1> to flag pte not found */
	mtctr	%r0			/* restore counter */
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	mtsrr1	%r2
	mtdsisr	%r1			/* load the dsisr */
	mfspr	%r1,DMISS		/* get the miss address */
	mtdar	%r1			/* put in dar */
	mfmsr	%r0
	xoris	%r0,%r0,2		/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
	ba	EXC_DSI
_C_LABEL(tlbdlmsize) =	.-_C_LABEL(tlbdlmiss)

	.globl	_C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
	.type	_C_LABEL(tlbdsmiss),@function
	.type	_C_LABEL(tlbdsmsize),@object
_C_LABEL(tlbdsmiss):
	mfspr	%r2,HASH1		/* get first pointer */
	li	%r1,8
	mfctr	%r0			/* save counter */
	mfspr	%r3,DCMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	lwzu	%r1,8(%r2)		/* get next pte */
	cmpl	0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	lwz	%r1,4(%r2)		/* load tlb entry lower word */
	andi.	%r3,%r1,0x80		/* check the C-bit */
	beq	4f
5:
	mtctr	%r0			/* restore counter */
	mfspr	%r0,DMISS		/* get the miss address for the tlbld */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	mtspr	RPA,%r1			/* set the pte */
	tlbld	0			/* load the dtlb */
	rfi

3:	/* not found in pteg */
	andi.	%r1,%r3,0x40		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,HASH2		/* get the second pointer */
	ori	%r3,%r3,0x40		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
4:	/* found, but C-bit = 0 */
	rlwinm.	%r3,%r1,30,0,1		/* test PP */
	bge-	7f
	andi.	%r3,%r1,1
	beq+	8f
9:	/* found, but protection violation (PP==00)*/
	mfsrr1	%r3
	lis	%r1,0xa00	/* indicate protection violation on store */
	b	1f
7:	/* found, PP=1x */
	mfspr	%r3,DMISS		/* get the miss address */
	mfsrin	%r1,%r3			/* get the segment register */
	mfsrr1	%r3
	rlwinm	%r3,%r3,18,31,31	/* get PR-bit */
	rlwnm.	%r1,%r1,%r3,1,1		/* get the key */
	bne-	9b			/* protection violation */
8:	/* found, set reference/change bits */
	lwz	%r1,4(%r2)		/* reload tlb entry */
	ori	%r1,%r1,0x180
	sth	%r1,6(%r2)
	b	5b
5:	/* not found anywhere */
	mfsrr1	%r3
	lis	%r1,0x4200		/* set dsisr<1> to flag pte not found */
					/* dsisr<6> to flag store */
1:
	mtctr	%r0			/* restore counter */
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	mtsrr1	%r2
	mtdsisr	%r1			/* load the dsisr */
	mfspr	%r1,DMISS		/* get the miss address */
	mtdar	%r1			/* put in dar */
	mfmsr	%r0
	xoris	%r0,%r0,2		/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
	ba	EXC_DSI
_C_LABEL(tlbdsmsize) =	.-_C_LABEL(tlbdsmiss)

#ifdef DDB
/*
 * In case of DDB we want a separate trap catcher for it
 */
	.globl	_C_LABEL(ddblow),_C_LABEL(ddbsize)
_C_LABEL(ddblow):
	mtsprg	1,%r1			/* save SP */
nop32_7s:
	mfmsr	%r1
	clrldi	%r1,%r1,1
	mtmsrd	%r1
nop32_7e:
	GET_CPUINFO(%r1)
	stmw	%r28,CI_DDBSAVE(%r1)	/* free r28-r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	GET_CPUINFO(%r30)
	lwz	%r30,CI_INTSTK(%r30)	/* get interrupt stack */
	addi	%r1,%r30,8192	 /* 7k for ddb */
	bla	ddbtrap
_C_LABEL(ddbsize) =	.-_C_LABEL(ddblow)
#endif  /* DDB */

/*
 * If this interrupt occured between the runqueue check and the setting
 * of the POW bit, do no enter to sleep.  We do that in order to process
 * the result of this interrupt directly and not when coming back from
 * sleep, when the next clock tick or interrupt will fire.
 */
#define CPU_IDLE_CHECK(sr1,sr2,sr3,rSRR0)				\
	GET_CPUINFO(sr1);						\
	lwz	sr2,CI_FLAGS(sr1);					\
	andi.	sr3,sr2,CI_FLAGS_SLEEPING@l;				\
	beq	1f;							\
	andi.	sr2,sr2,~CI_FLAGS_SLEEPING@l;				\
	stw	sr2,CI_FLAGS(sr1);					\
	lis	rSRR0,_C_LABEL(idledone)@ha;				\
	addi	rSRR0,rSRR0,_C_LABEL(idledone)@l;			\
1:

/*
 * FRAME_SETUP assumes:
 *	SPRG1		SP (1)
 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
 *	28		LR
 *	29		CR
 *	1		kernel stack
 *	LR		trap type
 *	SRR0/1		as at start of trap
 */
#define	FRAME_SETUP(savearea)						\
/* Have to enable translation to allow access of kernel stack: */	\
	GET_CPUINFO(%r31);						\
	mfsrr0	%r30;							\
	stw	%r30,savearea+24(%r31);					\
	mfsrr1	%r30;							\
	stw	%r30,savearea+28(%r31);					\
	/* load all kernel segment registers. */			\
	lis	%r31,_C_LABEL(kernel_pmap_)@ha;				\
	addi	%r31,%r31,_C_LABEL(kernel_pmap_)@l;			\
	lwz	%r30,0(%r31);	mtsr	0,%r30;				\
	lwz	%r30,4(%r31);	mtsr	1,%r30;				\
	lwz	%r30,8(%r31);	mtsr	2,%r30;				\
	lwz	%r30,12(%r31);	mtsr	3,%r30;				\
	lwz	%r30,16(%r31);	mtsr	4,%r30;				\
	lwz	%r30,20(%r31);	mtsr	5,%r30;				\
	lwz	%r30,24(%r31);	mtsr	6,%r30;				\
	lwz	%r30,28(%r31);	mtsr	7,%r30;				\
	lwz	%r30,32(%r31);	mtsr	8,%r30;				\
	lwz	%r30,36(%r31);	mtsr	9,%r30;				\
	lwz	%r30,40(%r31);	mtsr	10,%r30;			\
	lwz	%r30,44(%r31);	mtsr	11,%r30;			\
	lwz	%r30,48(%r31);	mtsr	12,%r30;			\
/*	lwz	%r30,52(%r31);	mtsr 13,%r30; - dont load user SR - XXX? */ \
	lwz	%r30,56(%r31);	mtsr	14,%r30;			\
	lwz	%r30,60(%r31);	mtsr	15,%r30;			\
	mfmsr	%r30;							\
	ori	%r30,%r30,(PSL_DR|PSL_IR);				\
	mtmsr	%r30;							\
	isync;								\
	mfsprg	%r31,1;							\
	stwu	%r31,-FRAMELEN(%r1);					\
	stw	%r0,FRAME_0+8(%r1);					\
	stw	%r31,FRAME_1+8(%r1);					\
	stw	%r2,FRAME_2+8(%r1);					\
	stw	%r28,FRAME_LR+8(%r1);					\
	stw	%r29,FRAME_CR+8(%r1);					\
	GET_CPUINFO(%r2);						\
	lmw	%r28,savearea(%r2);					\
	stmw	%r3,FRAME_3+8(%r1);					\
	lmw	%r28,savearea+16(%r2);					\
	mfxer	%r3;							\
	mfctr	%r4;							\
	mflr	%r5;							\
	andi.	%r5,%r5,0xff00;						\
	stw	%r3,FRAME_XER+8(%r1);					\
	stw	%r4,FRAME_CTR+8(%r1);					\
	stw	%r5,FRAME_EXC+8(%r1);					\
	stw	%r28,FRAME_DAR+8(%r1);					\
	stw	%r29,FRAME_DSISR+8(%r1);				\
	CPU_IDLE_CHECK(%r5,%r6,%r0,%r30)				\
	stw	%r30,FRAME_SRR0+8(%r1);					\
	stw	%r31,FRAME_SRR1+8(%r1)

#define	FRAME_LEAVE(savearea)						\
/* Now restore regs: */							\
	lwz	%r2,FRAME_SRR0+8(%r1);					\
	lwz	%r3,FRAME_SRR1+8(%r1);					\
	lwz	%r4,FRAME_CTR+8(%r1);					\
	lwz	%r5,FRAME_XER+8(%r1);					\
	lwz	%r6,FRAME_LR+8(%r1);					\
	GET_CPUINFO(%r7);						\
	stw	%r2,savearea(%r7);					\
	stw	%r3,savearea+4(%r7);					\
	lwz	%r7,FRAME_CR+8(%r1);					\
	mtctr	%r4;							\
	mtxer	%r5;							\
	mtlr	%r6;							\
	mtsprg	1,%r7;			/* save cr */			\
	lmw	%r2,FRAME_2+8(%r1);					\
	lwz	%r0,FRAME_0+8(%r1);					\
	lwz	%r1,FRAME_1+8(%r1);					\
	mtsprg	2,%r2;			/* save r2 & r3 */		\
	mtsprg	3,%r3;							\
/* Disable translation, machine check and recoverability: */		\
	mfmsr	%r2;							\
	lis	%r3,(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@ha;			\
	addi	%r3,%r3,(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;		\
	andc	%r2,%r2,%r3;						\
	mtmsr	%r2;							\
	isync;								\
/* Decide whether we return to user mode: */				\
	GET_CPUINFO(%r2);						\
	lwz	%r3,savearea+4(%r2);					\
	mtcr	%r3;							\
	bc	4,17,1f;		/* branch if PSL_PR is false */	\
/* Restore user & kernel access SR: */					\
	lwz	%r2,CI_CURPM(%r2);	/* get real address of pmap */	\
	lwz	%r3,0(%r2);	mtsr	0,%r3;				\
	lwz	%r3,4(%r2);	mtsr	1,%r3;				\
	lwz	%r3,8(%r2);	mtsr	2,%r3;				\
	lwz	%r3,12(%r2);	mtsr	3,%r3;				\
	lwz	%r3,16(%r2);	mtsr	4,%r3;				\
	lwz	%r3,20(%r2);	mtsr	5,%r3;				\
	lwz	%r3,24(%r2);	mtsr	6,%r3;				\
	lwz	%r3,28(%r2);	mtsr	7,%r3;				\
	lwz	%r3,32(%r2);	mtsr	8,%r3;				\
	lwz	%r3,36(%r2);	mtsr	9,%r3;				\
	lwz	%r3,40(%r2);	mtsr	10,%r3;				\
	lwz	%r3,44(%r2);	mtsr	11,%r3;				\
	lwz	%r3,48(%r2);	mtsr	12,%r3;				\
	lwz	%r3,52(%r2);	mtsr	13,%r3;				\
	lwz	%r3,56(%r2);	mtsr	14,%r3;				\
	lwz	%r3,60(%r2);	mtsr	15,%r3;				\
1:	mfsprg	%r2,1;			/* restore cr */		\
	mtcr	%r2;							\
	GET_CPUINFO(%r2);						\
	lwz	%r3,savearea(%r2);					\
	mtsrr0	%r3;							\
	lwz	%r3,savearea+4(%r2);					\
	mtsrr1	%r3;							\
	mfsprg	%r2,2;			/* restore r2 & r3 */		\
	mfsprg	%r3,3

/*
 * Preamble code for DSI/ISI traps
 */
disitrap:
	GET_CPUINFO(%r1)
	lmw	%r30,CI_DISISAVE(%r1)
	stmw	%r30,CI_TEMPSAVE(%r1)
	lmw	%r30,CI_DISISAVE+8(%r1)
	stmw	%r30,CI_TEMPSAVE+8(%r1)
	mfdar	%r30
	mfdsisr	%r31
	stmw	%r30,CI_TEMPSAVE+16(%r1)
realtrap:
	/* Test whether we already had PR set */
	mfsrr1	%r1
	mtcr	%r1
	/* restore SP (might have been overwritten) */
	mfsprg	%r1,1
	bc	4,17,s_trap		/* branch if PSL_PR is false */
	GET_CPUINFO(%r1)
	lwz	%r1,CI_CURPCB(%r1)
	addi	%r1,%r1,USPACE		/* stack is top of user struct */
/*
 * Now the common trap catching code.
 */
	.globl	s_trap
s_trap:
	FRAME_SETUP(CI_TEMPSAVE)
/* Now we can recover interrupts again: */
	mfmsr	%r7
	mfsrr1	%r31
	andi.	%r31,%r31,PSL_EE	/* restore EE from previous context */
	or	%r7,%r7,%r31
	ori	%r7,%r7,(PSL_ME|PSL_RI)
	mtmsr	%r7
	isync
/* Call C trap code: */
trapagain:
	addi	%r3,%r1,8
	bl	_C_LABEL(trap)

	.globl	trapexit
trapexit:
/* Disable interrupts: */
	mfmsr	%r3
	andi.	%r3,%r3,~PSL_EE@l
	mtmsr	%r3
/* Test AST pending: */
	lwz	%r5,FRAME_SRR1+8(%r1)
	mtcr	%r5
	bc	4,17,1f			/* branch if PSL_PR is false */
	GET_CPUINFO(%r3)
	lwz	%r4,CI_CURPROC(%r3)
	lwz	%r4,P_MD_ASTPENDING(%r4)
	andi.	%r4,%r4,1
	beq	1f
	li	%r6,EXC_AST
	stw	%r6,FRAME_EXC+8(%r1)
	b	trapagain
1:
	FRAME_LEAVE(CI_TEMPSAVE)
rfi1:	rfi

/*
 * Child comes here at the end of a fork.
 * Mostly similar to the above.
 */
	.globl	_C_LABEL(fork_trampoline)
	.type	_C_LABEL(fork_trampoline),@function
_C_LABEL(fork_trampoline):
#ifdef MULTIPROCESSOR
	bl	_C_LABEL(proc_trampoline_mp)
#endif
	li	%r3,0
	bl	_C_LABEL(lcsplx)
	mtlr	%r31
	mr	%r3,%r30
	blrl				/* jump indirect to r31 */
	b	trapexit

/*
 * DSI second stage fault handler
 */
s_dsitrap:
	mfdsisr	%r31			/* test if this is spill fault */
	mtcr	%r31
	mtsprg	1,%r1			/* save SP */
	bc	4,1,disitrap		/* branch if table miss is false */
	GET_CPUINFO(%r30)
	lwz	%r30,CI_INTSTK(%r30)	/* get interrupt stack */
	addi	%r1,%r30,1024
	stwu	%r1,-52(%r1)
	stw	%r0,48(%r1)		/* save non-volatile registers */
	stw	%r3,44(%r1)
	stw	%r4,40(%r1)
	stw	%r5,36(%r1)
	stw	%r6,32(%r1)
	stw	%r7,28(%r1)
	stw	%r8,24(%r1)
	stw	%r9,20(%r1)
	stw	%r10,16(%r1)
	stw	%r11,12(%r1)
	stw	%r12,8(%r1)
	mfxer	%r30			/* save XER */
	mtsprg	2,%r30
	mflr	%r30			/* save trap type */
	mfctr	%r31			/* & CTR */
	mfdar	%r7
	mfsrr1	%r4
	mfdsisr	%r5
	li	%r6, 0
s_pte_spill:
	andi.	%r0,%r4,PSL_PR
	li	%r3,0
	bne	1f
	mr	%r3,%r7
	bl	_C_LABEL(pte_spill_r)	/* try a spill */
1:
	cmpwi	0,%r3,0
	mtctr	%r31			/* restore CTR */
	mtlr	%r30			/* and trap type */
	mfsprg	%r31,2			/* get saved XER */
	mtxer	%r31			/* restore XER */
	lwz	%r12,8(%r1)		/* restore non-volatile registers */
	lwz	%r11,12(%r1)
	lwz	%r10,16(%r1)
	lwz	%r9,20(%r1)
	lwz	%r8,24(%r1)
	lwz	%r7,28(%r1)
	lwz	%r6,32(%r1)
	lwz	%r5,36(%r1)
	lwz	%r4,40(%r1)
	lwz	%r3,44(%r1)
	lwz	%r0,48(%r1)
	beq	disitrap
	mtcr	%r29			/* restore CR */
	mtlr	%r28			/* restore LR */
	GET_CPUINFO(%r1)
	lmw	%r28,CI_DISISAVE(%r1)	/* restore r28-r31 */
	mfsprg	%r1,1			/* restore SP */
rfi2:	rfi				/* return to trapped code */

/*
 * ISI second stage fault handler
 */
s_isitrap:
	mfsrr1	%r31			/* test if this may be a spill fault */
	mtcr	%r31
	mtsprg	1,%r1			/* save SP */
	bc	4,1,disitrap		/* branch if table miss is false */
	GET_CPUINFO(%r30)
	lwz	%r30,CI_INTSTK(%r30)	/* get interrupt stack */
	addi	%r1,%r30,1024
	stwu	%r1,-52(%r1)
	stw	%r0,48(%r1)		/* save non-volatile registers */
	stw	%r3,44(%r1)
	stw	%r4,40(%r1)
	stw	%r5,36(%r1)
	stw	%r6,32(%r1)
	stw	%r7,28(%r1)
	stw	%r8,24(%r1)
	stw	%r9,20(%r1)
	stw	%r10,16(%r1)
	stw	%r11,12(%r1)
	stw	%r12,8(%r1)
	mfxer	%r30			/* save XER */
	mtsprg	2,%r30
	mflr	%r30			/* save trap type */
	mfctr	%r31			/* & ctr */
	mfsrr0	%r7
	mfsrr1	%r4
	li	%r5, 0
	li	%r6, 1
	b	s_pte_spill		/* above */

/*
 * External interrupt second level handler
 */
#define	INTRENTER							\
/* Save non-volatile registers: */					\
	stwu	%r1,-88(%r1);		/* temporarily */		\
	stw	%r0,84(%r1);						\
	mfsprg	%r0,1;			/* get original SP */		\
	stw	%r0,0(%r1);		/* and store it */		\
	stw	%r3,80(%r1);						\
	stw	%r4,76(%r1);						\
	stw	%r5,72(%r1);						\
	stw	%r6,68(%r1);						\
	stw	%r7,64(%r1);						\
	stw	%r8,60(%r1);						\
	stw	%r9,56(%r1);						\
	stw	%r10,52(%r1);						\
	stw	%r11,48(%r1);						\
	stw	%r12,44(%r1);						\
	stw	%r28,40(%r1);		/* saved LR */			\
	stw	%r29,36(%r1);		/* saved CR */			\
	stw	%r30,32(%r1);		/* saved XER */			\
	GET_CPUINFO(%r4);						\
	lmw	%r28,CI_TEMPSAVE(%r4);	/* restore r28-r31 */		\
	mfctr	%r6;							\
	lwz	%r5,CI_INTRDEPTH(%r4);			\
	mfsrr0	%r4;							\
	mfsrr1	%r3;							\
	stw	%r6,28(%r1);						\
	stw	%r5,20(%r1);						\
	stw	%r4,12(%r1);						\
	stw	%r3,8(%r1);						\
/* load all kernel segment registers. */				\
	lis	3,_C_LABEL(kernel_pmap_)@ha;                            \
	addi	3,3,_C_LABEL(kernel_pmap_)@l;                           \
	lwz	%r5,0(%r3);	mtsr 0,%r5;				\
	lwz	%r5,4(%r3);	mtsr 1,%r5;				\
	lwz	%r5,8(%r3);	mtsr 2,%r5;				\
	lwz	%r5,12(%r3);	mtsr 3,%r5;				\
	lwz	%r5,16(%r3);	mtsr 4,%r5;				\
	lwz	%r5,20(%r3);	mtsr 5,%r5;				\
	lwz	%r5,24(%r3);	mtsr 6,%r5;				\
	lwz	%r5,28(%r3);	mtsr 7,%r5;				\
	lwz	%r5,32(%r3);	mtsr 8,%r5;				\
	lwz	%r5,36(%r3);	mtsr 9,%r5;				\
	lwz	%r5,40(%r3);	mtsr 10,%r5;				\
	lwz	%r5,44(%r3);	mtsr 11,%r5;				\
	lwz	%r5,48(%r3);	mtsr 12,%r5;				\
/*	lwz	%r5,52(%r3);	mtsr 13,%r5;	- dont load user SR - XXX? */ \
	lwz	%r5,56(%r3);	mtsr 14,%r5;				\
	lwz	%r5,60(%r3);	mtsr 15,%r5;				\
/* interrupts are recoverable here, and enable translation */		\
	mfmsr	%r5;							\
	ori	%r5,%r5,(PSL_IR|PSL_DR|PSL_RI);				\
	mtmsr	%r5;							\
	isync

	.globl	_C_LABEL(extint_call)
	.type	_C_LABEL(extint_call),@function
extintr:
	INTRENTER
_C_LABEL(extint_call):
	bl	_C_LABEL(ext_intr)		/* to be filled in later */
intr_exit:
/* Disable interrupts (should already be disabled) and MMU here: */
	mfmsr	%r3
	andi.	%r3,%r3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l
	mtmsr	%r3
	isync
/* restore possibly overwritten registers: */
	lwz	%r12,44(%r1)
	lwz	%r11,48(%r1)
	lwz	%r10,52(%r1)
	lwz	%r9,56(%r1)
	lwz	%r8,60(%r1)
	lwz	%r7,64(%r1)
	lwz	%r6,8(%r1)
	lwz	%r5,12(%r1)
	lwz	%r4,28(%r1)
	lwz	%r3,32(%r1)
	mtsrr1	%r6
	mtsrr0	%r5
	mtctr	%r4
	mtxer	%r3

	GET_CPUINFO(%r5)
	lwz	%r4,CI_INTRDEPTH(%r5)
	addi	%r4,%r4,-1		/* adjust reentrancy count */
	stw	%r4,CI_INTRDEPTH(%r5)

/* Returning to user mode? */
	mtcr	%r6			/* saved SRR1 */
	bc	4,17,1f			/* branch if PSL_PR is false */
	lwz	%r3,CI_CURPM(%r5)	/* get current pmap real address */
	/* reload all segment registers. */
	lwz	%r4,0(3);	mtsr 0,%r4;
	lwz	%r4,4(3);	mtsr 1,%r4;
	lwz	%r4,8(3);	mtsr 2,%r4;
	lwz	%r4,12(3);	mtsr 3,%r4;
	lwz	%r4,16(3);	mtsr 4,%r4;
	lwz	%r4,20(3);	mtsr 5,%r4;
	lwz	%r4,24(3);	mtsr 6,%r4;
	lwz	%r4,28(3);	mtsr 7,%r4;
	lwz	%r4,32(3);	mtsr 8,%r4;
	lwz	%r4,36(3);	mtsr 9,%r4;
	lwz	%r4,40(3);	mtsr 10,%r4;
	lwz	%r4,44(3);	mtsr 11,%r4;
	lwz	%r4,48(3);	mtsr 12,%r4;
	lwz	%r4,52(3);	mtsr 13,%r4;
	lwz	%r4,56(3);	mtsr 14,%r4;
	lwz	%r4,60(3);	mtsr 15,%r4;
	lwz	%r4,CI_CURPROC(%r5)
	lwz	%r4,P_MD_ASTPENDING(%r4)	/* Test AST pending */
	andi.	%r4,%r4,1
	beq	1f
/* Setup for entry to realtrap: */
	lwz	%r3,0(%r1)		/* get saved SP */
	mtsprg	1,%r3
	li	%r6,EXC_AST
	stmw	%r28,CI_TEMPSAVE(%r5)	/* establish tempsave again */
	mtlr	%r6
	lwz	%r28,40(%r1)		/* saved LR */
	lwz	%r29,36(%r1)		/* saved CR */
	lwz	%r6,68(%r1)
	lwz	%r5,72(%r1)
	lwz	%r4,76(%r1)
	lwz	%r3,80(%r1)
	lwz	%r0,84(%r1)
	b	realtrap
1:
/* Here is the normal exit of extintr: */
	lwz	%r5,36(%r1)
	lwz	%r6,40(%r1)
	mtcr	%r5
	mtlr	%r6
	lwz	%r6,68(%r1)
	lwz	%r5,72(%r1)
	lwz	%r4,76(%r1)
	lwz	%r3,80(%r1)
	lwz	%r0,84(%r1)
	lwz	%r1,0(%r1)
rfi3:	rfi

/*
 * Decrementer interrupt second level handler
 */
	.globl	decrintr
decrintr:
	INTRENTER
	addi	%r3,%r1,8			/* intr frame */
	bl	_C_LABEL(decr_intr)
	b	intr_exit

/*
 * int setfault()
 *
 * Similar to setjmp to setup for handling faults on accesses to user memory.
 * Any routine using this may only call bcopy, either the form below,
 * or the (currently used) C code optimized, so it doesn't use any non-volatile
 * registers.
 */
	.globl	_C_LABEL(setfault)
	.type	_C_LABEL(setfault),@function
_C_LABEL(setfault):
	mflr	%r0
	mfcr	%r12
	GET_CPUINFO(%r4)
	lwz	%r4,CI_CURPCB(%r4)
	stw	%r3,PCB_FAULT(%r4)
	stw	%r0,0(%r3)
	stw	%r1,4(%r3)
	stmw	%r12,8(%r3)
	li	%r3,0
	blr

/*
 * The following code gets copied to the top of the user stack on process
 * execution.  It does signal trampolining on signal delivery.
 *
 * On entry r1 points to a struct sigframe at bottom of current stack.
 * All other registers are unchanged.
 */
	.globl	_C_LABEL(sigcode),_C_LABEL(esigcode)
	.type	_C_LABEL(sigcode),@function
	.type	_C_LABEL(esigcode),@function
_C_LABEL(sigcode):
	addi	%r1,%r1,-((16+FPSIG_SIZEOF+15)& ~0xf)		/* reserved space for callee */
	addi	%r6,%r1,8
	stfd	%f0,0(%r6)
	stfd	%f1,8(%r6)
	stfd	%f2,16(%r6)
	stfd	%f3,24(%r6)
	stfd	%f4,32(%r6)
	stfd	%f5,40(%r6)
	stfd	%f6,48(%r6)
	stfd	%f7,56(%r6)
	stfd	%f8,64(%r6)
	stfd	%f9,72(%r6)
	stfd	%f10,80(%r6)
	stfd	%f11,88(%r6)
	stfd	%f12,96(%r6)
	stfd	%f13,104(%r6)
	mffs	%f0
	stfd	%f0,112(%r6)
	lfd	%f0,0(%r6)	/* restore the clobbered register */
	blrl
	addi	%r6,%r1,8
	lfd	%f0,112(%r6)
	mtfsf	0xff,%f0
	lfd	%f0,0(%r6)
	lfd	%f1,8(%r6)
	lfd	%f2,16(%r6)
	lfd	%f3,24(%r6)
	lfd	%f4,32(%r6)
	lfd	%f5,40(%r6)
	lfd	%f6,48(%r6)
	lfd	%f7,56(%r6)
	lfd	%f8,64(%r6)
	lfd	%f9,72(%r6)
	lfd	%f10,80(%r6)
	lfd	%f11,88(%r6)
	lfd	%f12,96(%r6)
	lfd	%f13,104(%r6)
	addi	%r3,%r1,((16+FPSIG_SIZEOF+15)&~0xf)+SF_SC	/* compute &sf_sc */
	li	%r0,SYS_sigreturn
	sc				/* sigreturn(scp) */
	li	%r0,SYS_exit
	sc				/* exit(errno) */
_C_LABEL(esigcode):

#ifdef DDB
/*
 * Deliberate entry to ddbtrap
 */
	.globl	_C_LABEL(ddb_trap)
_C_LABEL(ddb_trap):
	mtsprg	1,%r1
	mfmsr	%r3
	mtsrr1	%r3
	andi.	%r3,%r3,~(PSL_EE|PSL_ME)@l
	mtmsr	%r3				/* disable interrupts */
	isync
	GET_CPUINFO(%r3)
	stmw	%r28,CI_DDBSAVE(%r3)

	/*
	 * If we are already running in interrupt context, the CPU
	 * problably got interrupted while idle.  But since we are
	 * about to enter to ddb(8), do not let FRAME_SETUP() below
	 * change the return address of, and corrupt, this frame.
	 */
	lwz	%r28,CI_FLAGS(%r3)
	andi.	%r28,%r28,~CI_FLAGS_SLEEPING@l
	stw	%r28,CI_FLAGS(%r3)

	mflr	%r28
	li	%r29,EXC_BPT
	mtlr	%r29
	mfcr	%r29
	mtsrr0	%r28

/*
 * Now the ddb trap catching code.
 */
ddbtrap:
	FRAME_SETUP(CI_DDBSAVE)
/* Call C trap code: */
	addi	%r3,%r1,8
	bl	_C_LABEL(ddb_trap_glue)
	or.	%r3,%r3,%r3
	bne	ddbleave
/* This wasn't for DDB, so switch to real trap: */
	lwz	%r3,FRAME_EXC+8(%r1)	/* save exception */
	GET_CPUINFO(%r4)
	stw	%r3,CI_DDBSAVE+8(%r4)
	FRAME_LEAVE(CI_DDBSAVE)
	mtsprg	1,%r1			/* prepare for entrance to realtrap */
	GET_CPUINFO(%r1)
	stmw	%r28,CI_TEMPSAVE(%r1)
	mflr	%r28
	mfcr	%r29
	lwz	%r31,CI_DDBSAVE+8(%r1)
	mtlr	%r31
	b	realtrap
ddbleave:
	FRAME_LEAVE(CI_DDBSAVE)
rfi4:	rfi
#endif /* DDB */

	.globl  _C_LABEL(rfi_inst)
_C_LABEL(rfi_inst):
	rfi
	.globl  _C_LABEL(rfid_inst)
_C_LABEL(rfid_inst):
	rfid
	.globl  _C_LABEL(nop_inst)
 _C_LABEL(nop_inst):
	nop

	.globl  _C_LABEL(rfi_start)
_C_LABEL(rfi_start):
	.long	rfi1, rfi1 + 4
	.long	rfi2, rfi2 + 4
	.long	rfi3, rfi3 + 4
#ifdef DDB
	.long	rfi4, rfi4 + 4
#endif
	.long	0, 0

	.globl  _C_LABEL(nopbat_start)
_C_LABEL(nopbat_start):
	.long	nopbat_1s, nopbat_1e
	.long	0, 0

	.globl  _C_LABEL(nop32_start)
_C_LABEL(nop32_start):
	.long	nop32_1s, nop32_1e
	.long	nop32_2s, nop32_2e
	.long	nop32_3s, nop32_3e
	.long	nop32_4s, nop32_4e
	.long	nop32_5s, nop32_5e
	.long	nop32_6s, nop32_6e
#ifdef DDB
	.long	nop32_7s, nop32_7e
#endif
	.long	0, 0


code:
/*	$OpenBSD: machdep.c,v 1.64 2015/03/31 16:00:38 mpi Exp $	*/
/*	$NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $	*/

/*
 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
 * Copyright (C) 1995, 1996 TooLs GmbH.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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/buf.h>
#include <sys/conf.h>
#include <sys/exec.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/msgbuf.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/signalvar.h>
#include <sys/syscallargs.h>
#include <sys/sysctl.h>
#include <sys/tty.h>
#include <sys/user.h>

#include <net/if.h>
#include <uvm/uvm_extern.h>

#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/pio.h>
#include <powerpc/powerpc.h>
#include <machine/trap.h>

#include <dev/cons.h>

#include <dev/ic/comvar.h>

#ifdef DDB
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#endif

/*
 * Global variables used here and there
 */
extern struct user *proc0paddr;

struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };

struct vm_map *exec_map = NULL;
struct vm_map *phys_map = NULL;

/*
 * safepri is a safe priority for sleep to set for a spin-wait
 * during autoconfiguration or after a panic.
 */
int   safepri = 0;

int ppc_malloc_ok = 0;

char *bootpath;
char bootpathbuf[512];

struct bd_info {
	unsigned long	bi_memstart;
	unsigned long	bi_memsize;
	unsigned long	bi_flashstart;
	unsigned long	bi_flashsize;
	unsigned long	bi_flashoffset;
	unsigned long	bi_sramstart;
	unsigned long	bi_sramsize;
	unsigned long	bi_immr_base;
	unsigned long	bi_bootflags;
	unsigned long	bi_ip_addr;
	unsigned char	bi_enetaddr[6];
	unsigned long	bi_ethspeed;
} bootinfo;

extern struct bd_info **fwargsave;
extern struct fdt_head *fwfdtsave;

#ifdef APERTURE
#ifdef INSECURE
int allowaperture = 1;
#else
int allowaperture = 0;
#endif
#endif

void dumpsys(void);
int lcsplx(int ipl);
void myetheraddr(u_char *);

/*
 * Extent maps to manage I/O. Allocate storage for 8 regions in each,
 * initially. Later devio_malloc_safe will indicate that it's safe to
 * use malloc() to dynamically allocate region descriptors.
 */
static long devio_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof (long)];
struct extent *devio_ex;
static int devio_malloc_safe = 0;

void initppc(u_int, u_int, char *);

void prom_printf(const char *, ...);

extern struct ppc_bus_space mainbus_bus_space;

void
initppc(u_int startkernel, u_int endkernel, char *args)
{
	extern void *trapcode; extern int trapsize;
	extern void *extint; extern int extsize;
	extern void *dsitrap; extern int dsisize;
	extern void *isitrap; extern int isisize;
	extern void *alitrap; extern int alisize;
	extern void *decrint; extern int decrsize;
	extern void *tlbimiss; extern int tlbimsize;
	extern void *tlbdlmiss; extern int tlbdlmsize;
	extern void *tlbdsmiss; extern int tlbdsmsize;
#ifdef DDB
	extern void *ddblow; extern int ddbsize;
#endif
	extern void *msgbuf_addr;
	int exc;
	void *node;

	extern char __bss_start[], __end[];
	bzero(__bss_start, __end - __bss_start);

	/* Make a copy of the args! */
	strlcpy(bootpathbuf, args ? args : "wd0a", sizeof bootpathbuf);

	if (fwfdtsave && fwfdtsave->fh_magic == FDT_MAGIC) {
		/*
		 * Save the FDT firmware blob passed by the bootloader
		 * before we zero all memory.
		 *
		 */
		void *fdt = (void *)endkernel;
		memcpy(fdt, fwfdtsave, fwfdtsave->fh_size);
		endkernel += fwfdtsave->fh_size;

		fdt_init(fdt);

		/*
		 * XXX Create a fake bootinfo structure if we were
		 * loaded by RouterBOOT.
		 */
		node = fdt_find_node("/memory");
		if (node) {
			char *reg;

			if (fdt_node_property(node, "reg", &reg)) {
				bootinfo.bi_memstart = *(u_int32_t *)reg;
				bootinfo.bi_memsize = *((u_int32_t *)reg + 1);
			}
		}
		node = fdt_find_node("/soc8343");
		if (node) {
			char *reg;

			if (fdt_node_property(node, "reg", &reg))
				bootinfo.bi_immr_base = *(u_int32_t *)reg;
		}
		node = fdt_find_node("/soc8343/ethernet");
		if (node) {
			char *addr;

			if (fdt_node_property(node, "mac-address", &addr))
				memcpy(bootinfo.bi_enetaddr, addr, 6);
		}
	} else {
		/*
		 * We were loaded by an old U-Boot that didn't provide
		 * a flattened device tree.  It should have provided a
		 * valid bootinfo structure which we'll use to build
		 * such a device tree ourselves.
		 *
		 * XXX We don't build a flattened device tree yet.
		 */
		memcpy(&bootinfo, *fwargsave, sizeof bootinfo);

		extern uint8_t dt_blob_start[];
		fdt_init(&dt_blob_start);
	}

	proc0.p_cpu = &cpu_info[0];
	proc0.p_addr = proc0paddr;
	bzero(proc0.p_addr, sizeof *proc0.p_addr);

	curpcb = &proc0paddr->u_pcb;

	curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel();

	cpu_bootstrap();

	/*
	 * Initialize pmap module.
	 */
	pmap_bootstrap(startkernel, endkernel);

	/*
	 * Set up trap vectors
	 */
	for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100) {
		switch (exc) {
		default:
			bcopy(&trapcode, (void *)exc, (size_t)&trapsize);
			break;
		case EXC_EXI:
			bcopy(&extint, (void *)EXC_EXI, (size_t)&extsize);
			break;
		case EXC_DSI:
			bcopy(&dsitrap, (void *)EXC_DSI, (size_t)&dsisize);
			break;
		case EXC_ISI:
			bcopy(&isitrap, (void *)EXC_ISI, (size_t)&isisize);
			break;
		case EXC_ALI:
			bcopy(&alitrap, (void *)EXC_ALI, (size_t)&alisize);
			break;
		case EXC_DECR:
			bcopy(&decrint, (void *)EXC_DECR, (size_t)&decrsize);
			break;
		case EXC_IMISS:
			bcopy(&tlbimiss, (void *)EXC_IMISS, (size_t)&tlbimsize);
			break;
		case EXC_DLMISS:
			bcopy(&tlbdlmiss, (void *)EXC_DLMISS, (size_t)&tlbdlmsize);
			break;
		case EXC_DSMISS:
			bcopy(&tlbdsmiss, (void *)EXC_DSMISS, (size_t)&tlbdsmsize);
			break;
		case EXC_PGM:
		case EXC_TRC:
		case EXC_BPT:
#if defined(DDB)
			bcopy(&ddblow, (void *)exc, (size_t)&ddbsize);
#endif
			break;
		}
	}

	syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100);

	/*
	 * Now enable translation (and machine checks/recoverable interrupts).
	 */
	pmap_enable_mmu();

	/*
	 * use the memory provided by pmap_bootstrap for message buffer
	 */
	initmsgbuf(msgbuf_addr, MSGBUFSIZE);

	/*
	 * Look at arguments passed to us and compute boothowto.
	 */
	boothowto = RB_AUTOBOOT;

	/*
	 * Parse arg string.
	 */
	bootpath = &bootpathbuf[0];
	while (*++bootpath && *bootpath != ' ');
	if (*bootpath) {
		*bootpath++ = 0;
		while (*bootpath) {
			switch (*bootpath++) {
			case 'a':
				boothowto |= RB_ASKNAME;
				break;
			case 's':
				boothowto |= RB_SINGLE;
				break;
			case 'd':
				boothowto |= RB_KDB;
				break;
			case 'c':
				boothowto |= RB_CONFIG;
				break;
			default:
				break;
			}
		}
	}
	bootpath = &bootpathbuf[0];

#ifdef DDB
	ddb_init();
#endif

	/*
	 * Adjust base of internal memory mapped registers.
	 */
	mainbus_bus_space.bus_base = bootinfo.bi_immr_base;

	devio_ex = extent_create("devio", 0x80000000, 0xffffffff, M_DEVBUF,
		(caddr_t)devio_ex_storage, sizeof(devio_ex_storage),
		EX_NOCOALESCE|EX_NOWAIT);

	/*
	 * Initialize console.
	 */
	extern int comconsrate;
	comconsfreq = 266666666;
	comconsrate = 115200;
	comconsaddr = 0x00004500;
	comconsiot = &mainbus_bus_space;

	node = fdt_find_node("/chosen");
	if (node) {
		char *console;

		fdt_node_property(node, "linux,stdout-path", &console);
		node = fdt_find_node(console);
		if (node) {
			char *freq;
			char *reg;

			if (fdt_node_property(node, "clock-frequency", &freq))
				comconsfreq = *(u_int32_t *)freq;
			if (fdt_node_property(node, "reg", &reg))
				comconsaddr = *(u_int32_t *)reg;
		}
	}

	consinit();

#ifdef DDB
	if (boothowto & RB_KDB)
		Debugger();
#endif

	if (boothowto & RB_CONFIG) {
#ifdef BOOT_CONFIG
		user_config();
#else
		printf("kernel does not support -c; continuing..\n");
#endif
	}
}

void
dumpsys(void)
{
}

int cpu_imask[IPL_NUM];

int
lcsplx(int ipl)
{
	return spllower(ipl);
}

/*
 * Machine dependent startup code.
 */
void
cpu_startup()
{
	vaddr_t minaddr, maxaddr;

	proc0.p_addr = proc0paddr;

	printf("%s", version);

	printf("real mem = %lu (%luMB)\n", ptoa(physmem),
	    ptoa(physmem)/1024/1024);

	/*
	 * Allocate a submap for exec arguments.  This map effectively
	 * limits the number of processes exec'ing at any time.
	 */
	minaddr = vm_map_min(kernel_map);
	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 16 * NCARGS,
	    VM_MAP_PAGEABLE, FALSE, NULL);

	/*
	 * Allocate a submap for physio
	 */
	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
	    VM_PHYS_SIZE, 0, FALSE, NULL);
	ppc_malloc_ok = 1;

	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
	    ptoa(uvmexp.free) / 1024 / 1024);

	/*
	 * Set up the buffers.
	 */
	bufinit();

	devio_malloc_safe = 1;
}

/*
 * consinit
 * Initialize system console.
 */
void
consinit()
{
	static int cons_initted = 0;

	if (cons_initted)
		return;
	cninit();
	cons_initted = 1;
}

/*
 * Clear registers on exec
 */
void
setregs(struct proc *p, struct exec_package *pack, u_long stack,
    register_t *retval)
{
	u_int32_t newstack;
	u_int32_t pargs;
	u_int32_t args[4];

	struct trapframe *tf = trapframe(p);
	pargs = -roundup(-stack + 8, 16);
	newstack = (u_int32_t)(pargs - 32);

	copyin ((void *)p->p_p->ps_strings, &args, 0x10);

	bzero(tf, sizeof *tf);
	tf->fixreg[1] = newstack;
	tf->fixreg[3] = retval[0] = args[1];	/* XXX */
	tf->fixreg[4] = retval[1] = args[0];	/* XXX */
	tf->fixreg[5] = args[2];		/* XXX */
	tf->fixreg[6] = args[3];		/* XXX */
	tf->srr0 = pack->ep_entry;
	tf->srr1 = PSL_MBO | PSL_USERSET | PSL_FE_DFLT;
	p->p_addr->u_pcb.pcb_flags = 0;
}

/*
 * Send a signal to process.
 */
void
sendsig(sig_t catcher, int sig, int mask, u_long code, int type,
    union sigval val)
{
	struct proc *p = curproc;
	struct trapframe *tf;
	struct sigframe *fp, frame;
	struct sigacts *psp = p->p_p->ps_sigacts;

	bzero(&frame, sizeof(frame));
	frame.sf_signum = sig;

	tf = trapframe(p);

	/*
	 * Allocate stack space for signal handler.
	 */
	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
	    !sigonstack(tf->fixreg[1]) &&
	    (psp->ps_sigonstack & sigmask(sig)))
		fp = (struct sigframe *)(p->p_sigstk.ss_sp
					 + p->p_sigstk.ss_size);
	else
		fp = (struct sigframe *)tf->fixreg[1];

	fp = (struct sigframe *)((int)(fp - 1) & ~0xf);

	/*
	 * Generate signal context for SYS_sigreturn.
	 */
	frame.sf_sc.sc_mask = mask;
	frame.sf_sip = NULL;
	bcopy(tf, &frame.sf_sc.sc_frame, sizeof *tf);
	if (psp->ps_siginfo & sigmask(sig)) {
		frame.sf_sip = &fp->sf_si;
		initsiginfo(&frame.sf_si, sig, code, type, val);
	}
	if (copyout(&frame, fp, sizeof frame) != 0)
		sigexit(p, SIGILL);

	tf->fixreg[1] = (int)fp;
	tf->lr = (int)catcher;
	tf->fixreg[3] = (int)sig;
	tf->fixreg[4] = (psp->ps_siginfo & sigmask(sig)) ? (int)&fp->sf_si : 0;
	tf->fixreg[5] = (int)&fp->sf_sc;
	tf->srr0 = p->p_p->ps_sigcode;

#if WHEN_WE_ONLY_FLUSH_DATA_WHEN_DOING_PMAP_ENTER
	pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map),tf->srr0, &pa);
	syncicache(pa, (p->p_p->ps_emul->e_esigcode -
	    p->p_p->ps_emul->e_sigcode));
#endif
}

/*
 * System call to cleanup state after a signal handler returns.
 */
int
sys_sigreturn(struct proc *p, void *v, register_t *retval)
{
	struct sys_sigreturn_args /* {
		syscallarg(struct sigcontext *) sigcntxp;
	} */ *uap = v;
	struct sigcontext sc;
	struct trapframe *tf;
	int error;

	if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc)))
		return error;
	tf = trapframe(p);
	if ((sc.sc_frame.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC))
		return EINVAL;
	bcopy(&sc.sc_frame, tf, sizeof *tf);
	p->p_sigmask = sc.sc_mask & ~sigcantmask;
	return EJUSTRETURN;
}

/*
 * Machine dependent system variables.
 * None for now.
 */
int
cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
    size_t newlen, struct proc *p)
{
	/* all sysctl names at this level are terminal */
	if (namelen != 1)
		return ENOTDIR;
	switch (name[0]) {
	case CPU_ALLOWAPERTURE:
#ifdef APERTURE
		if (securelevel > 0)
			return (sysctl_int_lower(oldp, oldlenp, newp, newlen,
			    &allowaperture));
		else
			return (sysctl_int(oldp, oldlenp, newp, newlen,
			    &allowaperture));
#else
		return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif
	case CPU_ALTIVEC:
		return (sysctl_rdint(oldp, oldlenp, newp, 0));
	default:
		return EOPNOTSUPP;
	}
}

u_long dumpmag = 0x04959fca;			/* magic number */
int dumpsize = 0;			/* size of dump in pages */
long dumplo = -1;			/* blocks */

/*
 * This is called by configure to set dumplo and dumpsize.
 * Dumps always skip the first CLBYTES of disk space
 * in case there might be a disk label stored there.
 * If there is extra space, put dump at the end to
 * reduce the chance that swapping trashes it.
 */
void dumpconf(void);

void
dumpconf(void)
{
	int nblks;	/* size of dump area */
	int i;

	if (dumpdev == NODEV ||
	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
		return;
	if (nblks <= ctod(1))
		return;

	/* Always skip the first block, in case there is a label there. */
	if (dumplo < ctod(1))
		dumplo = ctod(1);

        for (i = 0; i < ndumpmem; i++)
		dumpsize = max(dumpsize, dumpmem[i].end);

	/* Put dump at end of partition, and make it fit. */
	if (dumpsize > dtoc(nblks - dumplo - 1))
		dumpsize = dtoc(nblks - dumplo - 1);
	if (dumplo < nblks - ctod(dumpsize) - 1)
		dumplo = nblks - ctod(dumpsize) - 1;

}

#define BYTES_PER_DUMP  (PAGE_SIZE)  /* must be a multiple of pagesize */
static vaddr_t dumpspace;

int
reserve_dumppages(caddr_t p)
{
	dumpspace = (vaddr_t)p;
	return BYTES_PER_DUMP;
}

/*
 * Halt or reboot the machine after syncing/dumping according to howto.
 */
__dead void
boot(int howto)
{
	static int syncing;

	if (cold) {
		if ((howto & RB_USERREQ) == 0)
			howto |= RB_HALT;
		goto haltsys;
	}

	boothowto = howto;
	if ((howto & RB_NOSYNC) == 0 && !syncing) {
		syncing = 1;
		vfs_shutdown();

		if ((howto & RB_TIMEBAD) == 0) {
			resettodr();
		} else {
			printf("WARNING: not updating battery clock\n");
		}
	}
	if_downall();

	uvm_shutdown();
	splhigh();
	cold = 1;

	if ((howto & RB_DUMP) != 0)
		dumpsys();

haltsys:
	config_suspend_all(DVACT_POWERDOWN);

	if ((howto & RB_HALT) != 0) {
		if ((howto & RB_POWERDOWN) != 0) {
			;
		}

		printf("halted\n\n");
		for (;;);
	}
	printf("rebooting\n\n");

	{
		volatile int32_t *reset;
		int32_t v;

		reset = mapiodev(0xe0000900, 0x100);
		reset[6] = 0x52535445;
		v = reset[6];
		reset[7] = 0x00000002;
	}

	printf("boot failed, spinning\n");
	for (;;) ;
	/* NOTREACHED */
}

/*
 * Notify the current process (p) that it has a signal pending,
 * process as soon as possible.
 */
void
signotify(struct proc *p)
{
	aston(p);
}

/* bcopy(), error on fault */
int
kcopy(const void *from, void *to, size_t size)
{
	faultbuf env;
	void *oldh = curproc->p_addr->u_pcb.pcb_onfault;

	if (setfault(&env)) {
		curproc->p_addr->u_pcb.pcb_onfault = oldh;
		return EFAULT;
	}
	bcopy(from, to, size);
	curproc->p_addr->u_pcb.pcb_onfault = oldh;

	return 0;
}

struct mem_region uboot_mem[2], uboot_avail[4];

void
ppc_mem_regions(struct mem_region **memp, struct mem_region **availp)
{
	uboot_mem[0].start = bootinfo.bi_memstart;
	uboot_mem[0].size = bootinfo.bi_memsize;

	/* Reserve memory used for exception vectors. */
	uboot_avail[0] = uboot_mem[0];
	if (uboot_mem[0].start < EXC_LAST + 0x100) {
		uboot_avail[0].size -= (EXC_LAST + 0x100 - uboot_mem[0].start);
		uboot_avail[0].start = EXC_LAST + 0x100;
	}

	*memp = uboot_mem;
	*availp = uboot_avail;
}

void
myetheraddr(u_char *cp)
{
	bcopy(bootinfo.bi_enetaddr, cp, sizeof bootinfo.bi_enetaddr);
	bootinfo.bi_enetaddr[5]++;
}

/* prototype for locore function */
void cpu_switchto_asm(struct proc *oldproc, struct proc *newproc);

void cpu_switchto(struct proc *oldproc, struct proc *newproc)
{
	cpu_switchto_asm(oldproc, newproc);
}

license: unknown


code:
/*	$OpenBSD: mainbus.c,v 1.6 2015/01/24 20:59:42 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * 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 and this permission notice 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.
 */

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

#include <machine/autoconf.h>

#include <dev/ofw/openfirm.h>

int	mainbus_match(struct device *, void *, void *);
void	mainbus_attach(struct device *, struct device *, void *);

struct cfattach mainbus_ca = {
	sizeof(struct device), mainbus_match, mainbus_attach
};

struct cfdriver mainbus_cd = {
	NULL, "mainbus", DV_DULL
};

struct ppc_bus_space mainbus_bus_space = { 0xff400000, 0x00100000, 0 };

struct powerpc_bus_dma_tag mainbus_bus_dma_tag = {
	NULL,
	_dmamap_create,
	_dmamap_destroy,
	_dmamap_load,
	_dmamap_load_mbuf,
	_dmamap_load_uio,
	_dmamap_load_raw,
	_dmamap_unload,
	_dmamap_sync,
	_dmamem_alloc,
	_dmamem_alloc_range,
	_dmamem_free,
	_dmamem_map,
	_dmamem_unmap,
	_dmamem_mmap
};

int	mainbus_print(void *, const char *);

int
mainbus_match(struct device *parent, void *cfdata, void *aux)
{
	return (1);
}

void
mainbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct mainbus_attach_args ma;
	char name[32];
	int node;

	printf("\n");

	ncpusfound = 0;
	node = OF_finddevice("/cpus");
	if (node != -1) {
		for (node = OF_child(node); node != 0; node = OF_peer(node)) {
			if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
				continue;

			bzero(&ma, sizeof(ma));
			ma.ma_name = name;
			ma.ma_node = node;
			config_found(self, &ma, mainbus_print);
			ncpusfound++;
		}
	}

	for (node = OF_child(OF_peer(0)); node != 0; node = OF_peer(node)) {
		if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
			continue;

		if (strcmp(name, "aliases") == 0 ||
		    strcmp(name, "chosen") == 0 ||
		    strcmp(name, "cpus") == 0 ||
		    strcmp(name, "memory") == 0)
			continue;

		bzero(&ma, sizeof(ma));
		ma.ma_iot = &mainbus_bus_space;
		ma.ma_dmat = &mainbus_bus_dma_tag;
		ma.ma_name = name;
		ma.ma_node = node;
		config_found(self, &ma, mainbus_print);
	}
}

int
mainbus_print(void *aux, const char *name)
{
	struct mainbus_attach_args *ma = aux;

	if (name)
		printf("\"%s\" at %s", ma->ma_name, name);

	return (UNCONF);
}


code:
/*	$OpenBSD: mem.c,v 1.4 2015/02/10 22:44:35 miod Exp $	*/
/*	$NetBSD: mem.c,v 1.1 1996/09/30 16:34:50 ws Exp $ */

/*
 * Copyright (c) 1988 University of Utah.
 * 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
 */

/*
 * Memory special file
 */

#include <sys/param.h>
#include <sys/buf.h>
#include <sys/systm.h>
#include <sys/ioccom.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/types.h>

#include <machine/cpu.h>

#include <uvm/uvm_extern.h>

#include <machine/conf.h>

/*ARGSUSED*/
int
mmopen(dev_t dev, int flag, int mode, struct proc *p)
{

	switch (minor(dev)) {
		case 0:
		case 1:
		case 2:
		case 12:
			break;
#ifdef xAPERTURE
	case 4:
	        if (suser(p, 0) != 0 || !allowaperture)
			return (EPERM);

		/* authorize only one simultaneous open() */
		if (ap_open_count > 0)
			return(EPERM);
		ap_open_count++;
		break;
#endif
		default:
			return (ENXIO);
	}
	return (0);
}

/*ARGSUSED*/
int
mmclose(dev_t dev, int flag, int mode, struct proc *p)
{
#ifdef xAPERTURE
	if (minor(dev) == 4)
		ap_open_count = 0;
#endif
	return 0;
}

/*ARGSUSED*/
int
mmrw(dev_t dev, struct uio *uio, int flags)
{
	vaddr_t v;
	vsize_t c;
	struct iovec *iov;
	int error = 0;
	static caddr_t zeropage;

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

		/* minor device 0 is physical memory */
		case 0:
			v = uio->uio_offset;
			c = uio->uio_resid;
			/* This doesn't allow device mapping!	XXX */
			pmap_real_memory(&v, &c);
			error = uiomove((caddr_t)v, c, uio);
			continue;

		/* minor device 1 is kernel memory */
		case 1:
			v = uio->uio_offset;
			c = ulmin(iov->iov_len, MAXPHYS);
			error = uiomove((caddr_t)v, c, uio);
			continue;

		/* minor device 2 is EOF/RATHOLE */
		case 2:
			if (uio->uio_rw == UIO_WRITE)
				uio->uio_resid = 0;
			return 0;

		/* minor device 12 (/dev/zero) is source of nulls on read,
		 * rathole on write
		 */
		case 12:
			if (uio->uio_rw == UIO_WRITE) {
				c = iov->iov_len;
				break;
			}
			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);
			continue;

		default:
			return ENXIO;
		}
		if (error)
			break;
		iov->iov_base += c;
		iov->iov_len -= c;
		uio->uio_offset += c;
		uio->uio_resid -= c;
	}
	return error;
}

paddr_t
mmmmap(dev_t dev, off_t off, int prot)
{
	return (-1);
}

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


code:
/*
 * Copyright (c) Mark Kettenis <kettenis@openbsd.org>
 *
 * 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 and this permission notice 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.
 */

/dts-v1/;

/ {
	model = "Thecus N1200";
	#address-cells = <1>;
	#size-cells = <1>;

	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		PowerPC,8347@0 {
			device_type = "cpu";
			reg = <0x0>;
			d-cache-line-size = <32>;
			i-cache-line-size = <32>;
			d-cache-size = <32768>;
			i-cache-size = <32768>;
			timebase-frequency = <66666666>;
			bus-frequency = <0>;	// XXX
			clock-frequency = <266666666>;
		};
	};

	memory {
		device_type = "memory";
		reg = <0x00000000 0x08000000>;	// 128MB at 0
	};

	soc8347@e0000000 {
		#address-cells = <1>;
		#size-cells = <1>;
		device_type = "soc";
		compatible = "simple-bus";
		ranges = <0x0 0xe0000000 0x00100000>;
		reg = <0xe0000000 0x00000200>;
		bus-frequency = <0>;

		wdt@200 {
			device_type = "watchdog";
			compatible = "mpc83xx_wdt";
			reg = <0x200 0x100>;
		};

		i2c@3000 {
			#address-cells = <1>;
			#size-cells = <0>;
			cell-index = <0>;
			compatible = "fsl-i2c";
			reg = <0x3000 0x100>;
			interrupts = <14 0x8>;
			interrupt-parent = <&ipic>;
			dfsrr;

			rtc@32 {
				compatible = "ricoh,rs5c372a";
				reg = <0x32>;
			};

			fan@2e {
				compatible = "fintek,f75375";
				reg = <0x2e>;
			};
		};

		i2c@3100 {
			#address-cells = <1>;
			#size-cells = <0>;
			cell-index = <1>;
			compatible = "fsl-i2c";
			reg = <0x3100 0x100>;
			interrupts = <15 0x8>;
			interrupt-parent = <&ipic>;
			dfsrr;
		};

		usb@22000 {
			compatible = "fsl-usb2-mph";
			reg = <0x22000 0x1000>;
			#address-cells = <1>;
			#size-cells = <0>;
			interrupt-parent = <&ipic>;
			interrupts = <39 0x8>;
			phy_type = "ulpi";
			port0;
			port1;
		};

		ethernet@24000 {
			#address-cells = <1>;
			#size-cells = <1>;
			cell-index = <0>;
			device_type = "network";
			model = "TSEC";
			compatible = "gianfar";
			reg = <0x24000 0x1000>;
			ranges = <0x0 0x24000 0x1000>;
			local-mac-address = [ 00 00 00 00 00 00 ];
			interrupts = <32 0x8 33 0x8 34 0x8>;
			interrupt-parent = <&ipic>;
			phy-handle = <&phy0>;

			mdio@520 {
				#address-cells = <1>;
				#size-cells = <0>;
				compatible = "fsl,gianfar-mdio";
				reg = <0x520 0x20>;

				phy0: ethernet-phy@11 {
					reg = <0x11>;
					device_type = "ethernet-phy";
				};

				phy1: ethernet-phy@5 {
					reg = <0x5>;
					device_type = "ethernet-phy";
				};
			};
		};

		ethernet@25000 {
			#address-cells = <1>;
			#size-cells = <1>;
			cell-index = <1>;
			device_type = "network";
			model = "TSEC";
			compatible = "gianfar";
			reg = <0x25000 0x1000>;
			ranges = <0x0 0x25000 0x1000>;
			local-mac-address = [ 00 00 00 00 00 00 ];
			interrupts = <35 0x8 36 0x8 37 0x8>;
			interrupt-parent = <&ipic>;
			phy-handle = <&phy1>;
		};

		serial0: serial@4500 {
			cell-index = <0>;
			device_type = "serial";
			compatible = "ns16550";
			reg = <0x4500 0x100>;
			clock-frequency = <266666666>;
			interrupts = <9 0x8>;
			interrupt-parent = <&ipic>;
		};

		ipic: pic@700 {
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			reg = <0x700 0x100>;
			device_type = "ipic";
		};
	};

	pci@e0008500 {
		cell-index = <1>;
		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
		interrupt-map = <0x8000 0x0 0x0 0x1 &ipic 20 0x8>;
		interrupt-parent = <&ipic>;
		interrupts = <66 0x8>;
		bus-range = <0 0>;
		ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x20000000
			  0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
		clock-frequency = <66666666>;
		#interrupt-cells = <1>;
		#size-cells = <2>;
		#address-cells = <3>;
		reg = <0xe0008500 0x100
		       0xe0008300 0x8>;
		compatible = "fsl,mpc8349-pci";
		device_type = "pci";
	};

	chosen {
	       linux,stdout-path = &serial0;
	};
};