| /* break.S: Break interrupt handling (kept separate from entry.S) | 
 |  * | 
 |  * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. | 
 |  * Written by David Howells (dhowells@redhat.com) | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU General Public License | 
 |  * as published by the Free Software Foundation; either version | 
 |  * 2 of the License, or (at your option) any later version. | 
 |  */ | 
 |  | 
 | #include <linux/linkage.h> | 
 | #include <asm/setup.h> | 
 | #include <asm/segment.h> | 
 | #include <asm/ptrace.h> | 
 | #include <asm/thread_info.h> | 
 | #include <asm/spr-regs.h> | 
 |  | 
 | #include <asm/errno.h> | 
 |  | 
 | # | 
 | # the break handler has its own stack | 
 | # | 
 | 	.section	.bss.stack | 
 | 	.globl		__break_user_context | 
 | 	.balign		THREAD_SIZE | 
 | __break_stack: | 
 | 	.space		THREAD_SIZE - FRV_FRAME0_SIZE | 
 | __break_frame_0: | 
 | 	.space		FRV_FRAME0_SIZE | 
 |  | 
 | # | 
 | # miscellaneous variables | 
 | # | 
 | 	.section	.bss | 
 | #ifdef CONFIG_MMU | 
 | 	.globl		__break_tlb_miss_real_return_info | 
 | __break_tlb_miss_real_return_info: | 
 | 	.balign		8 | 
 | 	.space		2*4			/* saved PCSR, PSR for TLB-miss handler fixup */ | 
 | #endif | 
 |  | 
 | __break_trace_through_exceptions: | 
 | 	.space		4 | 
 |  | 
 | #define CS2_ECS1	0xe1200000 | 
 | #define CS2_USERLED	0x4 | 
 |  | 
 | .macro LEDS val,reg | 
 | #	sethi.p		%hi(CS2_ECS1+CS2_USERLED),gr30 | 
 | #	setlo		%lo(CS2_ECS1+CS2_USERLED),gr30 | 
 | #	setlos		#~\val,\reg | 
 | #	st		\reg,@(gr30,gr0) | 
 | #	setlos		#0x5555,\reg | 
 | #	sethi.p		%hi(0xffc00100),gr30 | 
 | #	setlo		%lo(0xffc00100),gr30 | 
 | #	sth		\reg,@(gr30,gr0) | 
 | #	membar | 
 | .endm | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # entry point for Break Exceptions/Interrupts | 
 | # | 
 | ############################################################################### | 
 | 	.section	.text.break | 
 | 	.balign		4 | 
 | 	.globl		__entry_break | 
 | __entry_break: | 
 | #ifdef CONFIG_MMU | 
 | 	movgs		gr31,scr3 | 
 | #endif | 
 | 	LEDS		0x1001,gr31 | 
 |  | 
 | 	sethi.p		%hi(__break_frame_0),gr31 | 
 | 	setlo		%lo(__break_frame_0),gr31 | 
 |  | 
 | 	stdi		gr2,@(gr31,#REG_GR(2)) | 
 | 	movsg		ccr,gr3 | 
 | 	sti		gr3,@(gr31,#REG_CCR) | 
 |  | 
 | 	# catch the return from a TLB-miss handler that had single-step disabled | 
 | 	# traps will be enabled, so we have to do this now | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		bpcsr,gr3 | 
 | 	sethi.p		%hi(__break_tlb_miss_return_breaks_here),gr2 | 
 | 	setlo		%lo(__break_tlb_miss_return_breaks_here),gr2 | 
 | 	subcc		gr2,gr3,gr0,icc0 | 
 | 	beq		icc0,#2,__break_return_singlestep_tlbmiss | 
 | #endif | 
 |  | 
 | 	# determine whether we have stepped through into an exception | 
 | 	# - we need to take special action to suspend h/w single stepping if we've done | 
 | 	#   that, so that the gdbstub doesn't get bogged down endlessly stepping through | 
 | 	#   external interrupt handling | 
 | 	movsg		bpsr,gr3 | 
 | 	andicc		gr3,#BPSR_BET,gr0,icc0 | 
 | 	bne		icc0,#2,__break_maybe_userspace	/* jump if PSR.ET was 1 */ | 
 |  | 
 | 	LEDS		0x1003,gr2 | 
 |  | 
 | 	movsg		brr,gr3 | 
 | 	andicc		gr3,#BRR_ST,gr0,icc0 | 
 | 	andicc.p	gr3,#BRR_SB,gr0,icc1 | 
 | 	bne		icc0,#2,__break_step		/* jump if single-step caused break */ | 
 | 	beq		icc1,#2,__break_continue	/* jump if BREAK didn't cause break */ | 
 |  | 
 | 	LEDS		0x1007,gr2 | 
 |  | 
 | 	# handle special breaks | 
 | 	movsg		bpcsr,gr3 | 
 |  | 
 | 	sethi.p		%hi(__entry_return_singlestep_breaks_here),gr2 | 
 | 	setlo		%lo(__entry_return_singlestep_breaks_here),gr2 | 
 | 	subcc		gr2,gr3,gr0,icc0 | 
 | 	beq		icc0,#2,__break_return_singlestep | 
 |  | 
 | 	bra		__break_continue | 
 |  | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # handle BREAK instruction in kernel-mode exception epilogue | 
 | # | 
 | ############################################################################### | 
 | __break_return_singlestep: | 
 | 	LEDS		0x100f,gr2 | 
 |  | 
 | 	# special break insn requests single-stepping to be turned back on | 
 | 	#		HERE		RETT | 
 | 	# PSR.ET	0		0 | 
 | 	# PSR.PS	old PSR.S	? | 
 | 	# PSR.S		1		1 | 
 | 	# BPSR.ET	0		1 (can't have caused orig excep otherwise) | 
 | 	# BPSR.BS	1		old PSR.S | 
 | 	movsg		dcr,gr2 | 
 | 	sethi.p		%hi(DCR_SE),gr3 | 
 | 	setlo		%lo(DCR_SE),gr3 | 
 | 	or		gr2,gr3,gr2 | 
 | 	movgs		gr2,dcr | 
 |  | 
 | 	movsg		psr,gr2 | 
 | 	andi		gr2,#PSR_PS,gr2 | 
 | 	slli		gr2,#11,gr2			/* PSR.PS -> BPSR.BS */ | 
 | 	ori		gr2,#BPSR_BET,gr2		/* 1 -> BPSR.BET */ | 
 | 	movgs		gr2,bpsr | 
 |  | 
 | 	# return to the invoker of the original kernel exception | 
 | 	movsg		pcsr,gr2 | 
 | 	movgs		gr2,bpcsr | 
 |  | 
 | 	LEDS		0x101f,gr2 | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	lddi.p		@(gr31,#REG_GR(2)),gr2 | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # handle BREAK instruction in TLB-miss handler return path | 
 | # | 
 | ############################################################################### | 
 | #ifdef CONFIG_MMU | 
 | __break_return_singlestep_tlbmiss: | 
 | 	LEDS		0x1100,gr2 | 
 |  | 
 | 	sethi.p		%hi(__break_tlb_miss_real_return_info),gr3 | 
 | 	setlo		%lo(__break_tlb_miss_real_return_info),gr3 | 
 | 	lddi		@(gr3,#0),gr2 | 
 | 	movgs		gr2,pcsr | 
 | 	movgs		gr3,psr | 
 |  | 
 | 	bra		__break_return_singlestep | 
 | #endif | 
 |  | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # handle single stepping into an exception prologue from kernel mode | 
 | # - we try and catch it whilst it is still in the main vector table | 
 | # - if we catch it there, we have to jump to the fixup handler | 
 | #   - there is a fixup table that has a pointer for every 16b slot in the trap | 
 | #     table | 
 | # | 
 | ############################################################################### | 
 | __break_step: | 
 | 	LEDS		0x2003,gr2 | 
 |  | 
 | 	# external interrupts seem to escape from the trap table before single | 
 | 	# step catches up with them | 
 | 	movsg		bpcsr,gr2 | 
 | 	sethi.p		%hi(__entry_kernel_external_interrupt),gr3 | 
 | 	setlo		%lo(__entry_kernel_external_interrupt),gr3 | 
 | 	subcc.p		gr2,gr3,gr0,icc0 | 
 | 	sethi		%hi(__entry_uspace_external_interrupt),gr3 | 
 | 	setlo.p		%lo(__entry_uspace_external_interrupt),gr3 | 
 | 	beq		icc0,#2,__break_step_kernel_external_interrupt | 
 | 	subcc.p		gr2,gr3,gr0,icc0 | 
 | 	sethi		%hi(__entry_kernel_external_interrupt_virtually_disabled),gr3 | 
 | 	setlo.p		%lo(__entry_kernel_external_interrupt_virtually_disabled),gr3 | 
 | 	beq		icc0,#2,__break_step_uspace_external_interrupt | 
 | 	subcc.p		gr2,gr3,gr0,icc0 | 
 | 	sethi		%hi(__entry_kernel_external_interrupt_virtual_reenable),gr3 | 
 | 	setlo.p		%lo(__entry_kernel_external_interrupt_virtual_reenable),gr3 | 
 | 	beq		icc0,#2,__break_step_kernel_external_interrupt_virtually_disabled | 
 | 	subcc		gr2,gr3,gr0,icc0 | 
 | 	beq		icc0,#2,__break_step_kernel_external_interrupt_virtual_reenable | 
 |  | 
 | 	LEDS		0x2007,gr2 | 
 |  | 
 | 	# the two main vector tables are adjacent on one 8Kb slab | 
 | 	movsg		bpcsr,gr2 | 
 | 	setlos		#0xffffe000,gr3 | 
 | 	and		gr2,gr3,gr2 | 
 | 	sethi.p		%hi(__trap_tables),gr3 | 
 | 	setlo		%lo(__trap_tables),gr3 | 
 | 	subcc		gr2,gr3,gr0,icc0 | 
 | 	bne		icc0,#2,__break_continue | 
 |  | 
 | 	LEDS		0x200f,gr2 | 
 |  | 
 | 	# skip workaround if so requested by GDB | 
 | 	sethi.p		%hi(__break_trace_through_exceptions),gr3 | 
 | 	setlo		%lo(__break_trace_through_exceptions),gr3 | 
 | 	ld		@(gr3,gr0),gr3 | 
 | 	subcc		gr3,gr0,gr0,icc0 | 
 | 	bne		icc0,#0,__break_continue | 
 |  | 
 | 	LEDS		0x201f,gr2 | 
 |  | 
 | 	# access the fixup table - there's a 1:1 mapping between the slots in the trap tables and | 
 | 	# the slots in the trap fixup tables allowing us to simply divide the offset into the | 
 | 	# former by 4 to access the latter | 
 | 	sethi.p		%hi(__trap_tables),gr3 | 
 | 	setlo		%lo(__trap_tables),gr3 | 
 | 	movsg		bpcsr,gr2 | 
 | 	sub		gr2,gr3,gr2 | 
 | 	srli.p		gr2,#2,gr2 | 
 |  | 
 | 	sethi		%hi(__trap_fixup_tables),gr3 | 
 | 	setlo.p		%lo(__trap_fixup_tables),gr3 | 
 | 	andi		gr2,#~3,gr2 | 
 | 	ld		@(gr2,gr3),gr2 | 
 | 	jmpil		@(gr2,#0) | 
 |  | 
 | # step through an internal exception from kernel mode | 
 | 	.globl		__break_step_kernel_softprog_interrupt | 
 | __break_step_kernel_softprog_interrupt: | 
 | 	sethi.p		%hi(__entry_kernel_softprog_interrupt_reentry),gr3 | 
 | 	setlo		%lo(__entry_kernel_softprog_interrupt_reentry),gr3 | 
 | 	bra		__break_return_as_kernel_prologue | 
 |  | 
 | # step through an external interrupt from kernel mode | 
 | 	.globl		__break_step_kernel_external_interrupt | 
 | __break_step_kernel_external_interrupt: | 
 | 	# deal with virtual interrupt disablement | 
 | 	beq		icc2,#0,__break_step_kernel_external_interrupt_virtually_disabled | 
 |  | 
 | 	sethi.p		%hi(__entry_kernel_external_interrupt_reentry),gr3 | 
 | 	setlo		%lo(__entry_kernel_external_interrupt_reentry),gr3 | 
 |  | 
 | __break_return_as_kernel_prologue: | 
 | 	LEDS		0x203f,gr2 | 
 |  | 
 | 	movgs		gr3,bpcsr | 
 |  | 
 | 	# do the bit we had to skip | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		ear0,gr2		/* EAR0 can get clobbered by gdb-stub (ICI/ICEI) */ | 
 | 	movgs		gr2,scr2 | 
 | #endif | 
 |  | 
 | 	or.p		sp,gr0,gr2		/* set up the stack pointer */ | 
 | 	subi		sp,#REG__END,sp | 
 | 	sti.p		gr2,@(sp,#REG_SP) | 
 |  | 
 | 	setlos		#REG__STATUS_STEP,gr2 | 
 | 	sti		gr2,@(sp,#REG__STATUS)		/* record single step status */ | 
 |  | 
 | 	# cancel single-stepping mode | 
 | 	movsg		dcr,gr2 | 
 | 	sethi.p		%hi(~DCR_SE),gr3 | 
 | 	setlo		%lo(~DCR_SE),gr3 | 
 | 	and		gr2,gr3,gr2 | 
 | 	movgs		gr2,dcr | 
 |  | 
 | 	LEDS		0x207f,gr2 | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	lddi.p		@(gr31,#REG_GR(2)),gr2 | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | # we single-stepped into an interrupt handler whilst interrupts were merely virtually disabled | 
 | # need to really disable interrupts, set flag, fix up and return | 
 | __break_step_kernel_external_interrupt_virtually_disabled: | 
 | 	movsg		psr,gr2 | 
 | 	andi		gr2,#~PSR_PIL,gr2 | 
 | 	ori		gr2,#PSR_PIL_14,gr2	/* debugging interrupts only */ | 
 | 	movgs		gr2,psr | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	subcc.p		gr0,gr0,gr0,icc2	/* leave Z set, clear C */ | 
 |  | 
 | 	# exceptions must've been enabled and we must've been in supervisor mode | 
 | 	setlos		BPSR_BET|BPSR_BS,gr3 | 
 | 	movgs		gr3,bpsr | 
 |  | 
 | 	# return to where the interrupt happened | 
 | 	movsg		pcsr,gr2 | 
 | 	movgs		gr2,bpcsr | 
 |  | 
 | 	lddi.p		@(gr31,#REG_GR(2)),gr2 | 
 |  | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | # we stepped through into the virtual interrupt reenablement trap | 
 | # | 
 | # we also want to single step anyway, but after fixing up so that we get an event on the | 
 | # instruction after the broken-into exception returns | 
 | 	.globl		__break_step_kernel_external_interrupt_virtual_reenable | 
 | __break_step_kernel_external_interrupt_virtual_reenable: | 
 | 	movsg		psr,gr2 | 
 | 	andi		gr2,#~PSR_PIL,gr2 | 
 | 	movgs		gr2,psr | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	subicc		gr0,#1,gr0,icc2		/* clear Z, set C */ | 
 |  | 
 | 	# save the adjusted ICC2 | 
 | 	movsg		ccr,gr3 | 
 | 	sti		gr3,@(gr31,#REG_CCR) | 
 |  | 
 | 	# exceptions must've been enabled and we must've been in supervisor mode | 
 | 	setlos		BPSR_BET|BPSR_BS,gr3 | 
 | 	movgs		gr3,bpsr | 
 |  | 
 | 	# return to where the trap happened | 
 | 	movsg		pcsr,gr2 | 
 | 	movgs		gr2,bpcsr | 
 |  | 
 | 	# and then process the single step | 
 | 	bra		__break_continue | 
 |  | 
 | # step through an internal exception from uspace mode | 
 | 	.globl		__break_step_uspace_softprog_interrupt | 
 | __break_step_uspace_softprog_interrupt: | 
 | 	sethi.p		%hi(__entry_uspace_softprog_interrupt_reentry),gr3 | 
 | 	setlo		%lo(__entry_uspace_softprog_interrupt_reentry),gr3 | 
 | 	bra		__break_return_as_uspace_prologue | 
 |  | 
 | # step through an external interrupt from kernel mode | 
 | 	.globl		__break_step_uspace_external_interrupt | 
 | __break_step_uspace_external_interrupt: | 
 | 	sethi.p		%hi(__entry_uspace_external_interrupt_reentry),gr3 | 
 | 	setlo		%lo(__entry_uspace_external_interrupt_reentry),gr3 | 
 |  | 
 | __break_return_as_uspace_prologue: | 
 | 	LEDS		0x20ff,gr2 | 
 |  | 
 | 	movgs		gr3,bpcsr | 
 |  | 
 | 	# do the bit we had to skip | 
 | 	sethi.p		%hi(__kernel_frame0_ptr),gr28 | 
 | 	setlo		%lo(__kernel_frame0_ptr),gr28 | 
 | 	ldi.p		@(gr28,#0),gr28 | 
 |  | 
 | 	setlos		#REG__STATUS_STEP,gr2 | 
 | 	sti		gr2,@(gr28,#REG__STATUS)	/* record single step status */ | 
 |  | 
 | 	# cancel single-stepping mode | 
 | 	movsg		dcr,gr2 | 
 | 	sethi.p		%hi(~DCR_SE),gr3 | 
 | 	setlo		%lo(~DCR_SE),gr3 | 
 | 	and		gr2,gr3,gr2 | 
 | 	movgs		gr2,dcr | 
 |  | 
 | 	LEDS		0x20fe,gr2 | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	lddi.p		@(gr31,#REG_GR(2)),gr2 | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | #ifdef CONFIG_MMU | 
 | # step through an ITLB-miss handler from user mode | 
 | 	.globl		__break_user_insn_tlb_miss | 
 | __break_user_insn_tlb_miss: | 
 | 	# we'll want to try the trap stub again | 
 | 	sethi.p		%hi(__trap_user_insn_tlb_miss),gr2 | 
 | 	setlo		%lo(__trap_user_insn_tlb_miss),gr2 | 
 | 	movgs		gr2,bpcsr | 
 |  | 
 | __break_tlb_miss_common: | 
 | 	LEDS		0x2101,gr2 | 
 |  | 
 | 	# cancel single-stepping mode | 
 | 	movsg		dcr,gr2 | 
 | 	sethi.p		%hi(~DCR_SE),gr3 | 
 | 	setlo		%lo(~DCR_SE),gr3 | 
 | 	and		gr2,gr3,gr2 | 
 | 	movgs		gr2,dcr | 
 |  | 
 | 	# we'll swap the real return address for one with a BREAK insn so that we can re-enable | 
 | 	# single stepping on return | 
 | 	movsg		pcsr,gr2 | 
 | 	sethi.p		%hi(__break_tlb_miss_real_return_info),gr3 | 
 | 	setlo		%lo(__break_tlb_miss_real_return_info),gr3 | 
 | 	sti		gr2,@(gr3,#0) | 
 |  | 
 | 	sethi.p		%hi(__break_tlb_miss_return_break),gr2 | 
 | 	setlo		%lo(__break_tlb_miss_return_break),gr2 | 
 | 	movgs		gr2,pcsr | 
 |  | 
 | 	# we also have to fudge PSR because the return BREAK is in kernel space and we want | 
 | 	# to get a BREAK fault not an access violation should the return be to userspace | 
 | 	movsg		psr,gr2 | 
 | 	sti.p		gr2,@(gr3,#4) | 
 | 	ori		gr2,#PSR_PS,gr2 | 
 | 	movgs		gr2,psr | 
 |  | 
 | 	LEDS		0x2102,gr2 | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	lddi		@(gr31,#REG_GR(2)),gr2 | 
 | 	movsg		scr3,gr31 | 
 | 	movgs		gr0,brr | 
 | 	rett		#1 | 
 |  | 
 | # step through a DTLB-miss handler from user mode | 
 | 	.globl		__break_user_data_tlb_miss | 
 | __break_user_data_tlb_miss: | 
 | 	# we'll want to try the trap stub again | 
 | 	sethi.p		%hi(__trap_user_data_tlb_miss),gr2 | 
 | 	setlo		%lo(__trap_user_data_tlb_miss),gr2 | 
 | 	movgs		gr2,bpcsr | 
 | 	bra		__break_tlb_miss_common | 
 |  | 
 | # step through an ITLB-miss handler from kernel mode | 
 | 	.globl		__break_kernel_insn_tlb_miss | 
 | __break_kernel_insn_tlb_miss: | 
 | 	# we'll want to try the trap stub again | 
 | 	sethi.p		%hi(__trap_kernel_insn_tlb_miss),gr2 | 
 | 	setlo		%lo(__trap_kernel_insn_tlb_miss),gr2 | 
 | 	movgs		gr2,bpcsr | 
 | 	bra		__break_tlb_miss_common | 
 |  | 
 | # step through a DTLB-miss handler from kernel mode | 
 | 	.globl		__break_kernel_data_tlb_miss | 
 | __break_kernel_data_tlb_miss: | 
 | 	# we'll want to try the trap stub again | 
 | 	sethi.p		%hi(__trap_kernel_data_tlb_miss),gr2 | 
 | 	setlo		%lo(__trap_kernel_data_tlb_miss),gr2 | 
 | 	movgs		gr2,bpcsr | 
 | 	bra		__break_tlb_miss_common | 
 | #endif | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # handle debug events originating with userspace | 
 | # | 
 | ############################################################################### | 
 | __break_maybe_userspace: | 
 | 	LEDS		0x3003,gr2 | 
 |  | 
 | 	setlos		#BPSR_BS,gr2 | 
 | 	andcc		gr3,gr2,gr0,icc0 | 
 | 	bne		icc0,#0,__break_continue	/* skip if PSR.S was 1 */ | 
 |  | 
 | 	movsg		brr,gr2 | 
 | 	andicc		gr2,#BRR_ST|BRR_SB,gr0,icc0 | 
 | 	beq		icc0,#0,__break_continue	/* jump if not BREAK or single-step */ | 
 |  | 
 | 	LEDS		0x3007,gr2 | 
 |  | 
 | 	# do the first part of the exception prologue here | 
 | 	sethi.p		%hi(__kernel_frame0_ptr),gr28 | 
 | 	setlo		%lo(__kernel_frame0_ptr),gr28 | 
 | 	ldi		@(gr28,#0),gr28 | 
 | 	andi		gr28,#~7,gr28 | 
 |  | 
 | 	# set up the kernel stack pointer | 
 | 	sti		sp  ,@(gr28,#REG_SP) | 
 | 	ori		gr28,0,sp | 
 | 	sti		gr0 ,@(gr28,#REG_GR(28)) | 
 |  | 
 | 	stdi		gr20,@(gr28,#REG_GR(20)) | 
 | 	stdi		gr22,@(gr28,#REG_GR(22)) | 
 |  | 
 | 	movsg		tbr,gr20 | 
 | 	movsg		bpcsr,gr21 | 
 | 	movsg		psr,gr22 | 
 |  | 
 | 	# determine the exception type and cancel single-stepping mode | 
 | 	or		gr0,gr0,gr23 | 
 |  | 
 | 	movsg		dcr,gr2 | 
 | 	sethi.p		%hi(DCR_SE),gr3 | 
 | 	setlo		%lo(DCR_SE),gr3 | 
 | 	andcc		gr2,gr3,gr0,icc0 | 
 | 	beq		icc0,#0,__break_no_user_sstep	/* must have been a BREAK insn */ | 
 |  | 
 | 	not		gr3,gr3 | 
 | 	and		gr2,gr3,gr2 | 
 | 	movgs		gr2,dcr | 
 | 	ori		gr23,#REG__STATUS_STEP,gr23 | 
 |  | 
 | __break_no_user_sstep: | 
 | 	LEDS		0x300f,gr2 | 
 |  | 
 | 	movsg		brr,gr2 | 
 | 	andi		gr2,#BRR_ST|BRR_SB,gr2 | 
 | 	slli		gr2,#1,gr2 | 
 | 	or		gr23,gr2,gr23 | 
 | 	sti.p		gr23,@(gr28,#REG__STATUS)	/* record single step status */ | 
 |  | 
 | 	# adjust the value acquired from TBR - this indicates the exception | 
 | 	setlos		#~TBR_TT,gr2 | 
 | 	and.p		gr20,gr2,gr20 | 
 | 	setlos		#TBR_TT_BREAK,gr2 | 
 | 	or.p		gr20,gr2,gr20 | 
 |  | 
 | 	# fudge PSR.PS and BPSR.BS to return to kernel mode through the trap | 
 | 	# table as trap 126 | 
 | 	andi		gr22,#~PSR_PS,gr22		/* PSR.PS should be 0 */ | 
 | 	movgs		gr22,psr | 
 |  | 
 | 	setlos		#BPSR_BS,gr2			/* BPSR.BS should be 1 and BPSR.BET 0 */ | 
 | 	movgs		gr2,bpsr | 
 |  | 
 | 	# return through remainder of the exception prologue | 
 | 	# - need to load gr23 with return handler address | 
 | 	sethi.p		%hi(__entry_return_from_user_exception),gr23 | 
 | 	setlo		%lo(__entry_return_from_user_exception),gr23 | 
 | 	sethi.p		%hi(__entry_common),gr3 | 
 | 	setlo		%lo(__entry_common),gr3 | 
 | 	movgs		gr3,bpcsr | 
 |  | 
 | 	LEDS		0x301f,gr2 | 
 |  | 
 | 	ldi		@(gr31,#REG_CCR),gr3 | 
 | 	movgs		gr3,ccr | 
 | 	lddi.p		@(gr31,#REG_GR(2)),gr2 | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | ############################################################################### | 
 | # | 
 | # resume normal debug-mode entry | 
 | # | 
 | ############################################################################### | 
 | __break_continue: | 
 | 	LEDS		0x4003,gr2 | 
 |  | 
 | 	# set up the kernel stack pointer | 
 | 	sti		sp,@(gr31,#REG_SP) | 
 |  | 
 | 	sethi.p		%hi(__break_frame_0),sp | 
 | 	setlo		%lo(__break_frame_0),sp | 
 |  | 
 | 	# finish building the exception frame | 
 | 	stdi		gr4 ,@(gr31,#REG_GR(4)) | 
 | 	stdi		gr6 ,@(gr31,#REG_GR(6)) | 
 | 	stdi		gr8 ,@(gr31,#REG_GR(8)) | 
 | 	stdi		gr10,@(gr31,#REG_GR(10)) | 
 | 	stdi		gr12,@(gr31,#REG_GR(12)) | 
 | 	stdi		gr14,@(gr31,#REG_GR(14)) | 
 | 	stdi		gr16,@(gr31,#REG_GR(16)) | 
 | 	stdi		gr18,@(gr31,#REG_GR(18)) | 
 | 	stdi		gr20,@(gr31,#REG_GR(20)) | 
 | 	stdi		gr22,@(gr31,#REG_GR(22)) | 
 | 	stdi		gr24,@(gr31,#REG_GR(24)) | 
 | 	stdi		gr26,@(gr31,#REG_GR(26)) | 
 | 	sti		gr0 ,@(gr31,#REG_GR(28))	/* NULL frame pointer */ | 
 | 	sti		gr29,@(gr31,#REG_GR(29)) | 
 | 	sti		gr30,@(gr31,#REG_GR(30)) | 
 | 	sti		gr8 ,@(gr31,#REG_ORIG_GR8) | 
 |  | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr19 | 
 | 	sti		gr19,@(gr31,#REG_GR(31)) | 
 | #endif | 
 |  | 
 | 	movsg		bpsr ,gr19 | 
 | 	movsg		tbr  ,gr20 | 
 | 	movsg		bpcsr,gr21 | 
 | 	movsg		psr  ,gr22 | 
 | 	movsg		isr  ,gr23 | 
 | 	movsg		cccr ,gr25 | 
 | 	movsg		lr   ,gr26 | 
 | 	movsg		lcr  ,gr27 | 
 |  | 
 | 	andi.p		gr22,#~(PSR_S|PSR_ET),gr5	/* rebuild PSR */ | 
 | 	andi		gr19,#PSR_ET,gr4 | 
 | 	or.p		gr4,gr5,gr5 | 
 | 	srli		gr19,#10,gr4 | 
 | 	andi		gr4,#PSR_S,gr4 | 
 | 	or.p		gr4,gr5,gr5 | 
 |  | 
 | 	setlos		#-1,gr6 | 
 | 	sti		gr20,@(gr31,#REG_TBR) | 
 | 	sti		gr21,@(gr31,#REG_PC) | 
 | 	sti		gr5 ,@(gr31,#REG_PSR) | 
 | 	sti		gr23,@(gr31,#REG_ISR) | 
 | 	sti		gr25,@(gr31,#REG_CCCR) | 
 | 	stdi		gr26,@(gr31,#REG_LR) | 
 | 	sti		gr6 ,@(gr31,#REG_SYSCALLNO) | 
 |  | 
 | 	# store CPU-specific regs | 
 | 	movsg		iacc0h,gr4 | 
 | 	movsg		iacc0l,gr5 | 
 | 	stdi		gr4,@(gr31,#REG_IACC0) | 
 |  | 
 | 	movsg		gner0,gr4 | 
 | 	movsg		gner1,gr5 | 
 | 	stdi		gr4,@(gr31,#REG_GNER0) | 
 |  | 
 | 	# build the debug register frame | 
 | 	movsg		brr,gr4 | 
 | 	movgs		gr0,brr | 
 | 	movsg		nmar,gr5 | 
 | 	movsg		dcr,gr6 | 
 |  | 
 | 	sethi.p		%hi(__debug_status),gr7 | 
 | 	setlo		%lo(__debug_status),gr7 | 
 |  | 
 | 	stdi		gr4 ,@(gr7,#DEBUG_BRR) | 
 | 	sti		gr19,@(gr7,#DEBUG_BPSR) | 
 | 	sti.p		gr6 ,@(gr7,#DEBUG_DCR) | 
 |  | 
 | 	# trap exceptions during break handling and disable h/w breakpoints/watchpoints | 
 | 	sethi		%hi(DCR_EBE),gr5 | 
 | 	setlo.p		%lo(DCR_EBE),gr5 | 
 | 	sethi		%hi(__entry_breaktrap_table),gr4 | 
 | 	setlo		%lo(__entry_breaktrap_table),gr4 | 
 | 	movgs		gr5,dcr | 
 | 	movgs		gr4,tbr | 
 |  | 
 | 	# set up kernel global registers | 
 | 	sethi.p		%hi(__kernel_current_task),gr5 | 
 | 	setlo		%lo(__kernel_current_task),gr5 | 
 | 	ld		@(gr5,gr0),gr29 | 
 | 	ldi.p		@(gr29,#4),gr15		; __current_thread_info = current->thread_info | 
 |  | 
 | 	sethi		%hi(_gp),gr16 | 
 | 	setlo.p		%lo(_gp),gr16 | 
 |  | 
 | 	# make sure we (the kernel) get div-zero and misalignment exceptions | 
 | 	setlos		#ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5 | 
 | 	movgs		gr5,isr | 
 |  | 
 | 	# enter the GDB stub | 
 | 	LEDS		0x4007,gr2 | 
 |  | 
 | 	or.p		gr0,gr0,fp | 
 | 	call		debug_stub | 
 |  | 
 | 	LEDS		0x403f,gr2 | 
 |  | 
 | 	# return from break | 
 | 	lddi		@(gr31,#REG_IACC0),gr4 | 
 | 	movgs		gr4,iacc0h | 
 | 	movgs		gr5,iacc0l | 
 |  | 
 | 	lddi		@(gr31,#REG_GNER0),gr4 | 
 | 	movgs		gr4,gner0 | 
 | 	movgs		gr5,gner1 | 
 |  | 
 | 	lddi		@(gr31,#REG_LR)  ,gr26 | 
 | 	lddi		@(gr31,#REG_CCR) ,gr24 | 
 | 	lddi		@(gr31,#REG_PSR) ,gr22 | 
 | 	ldi		@(gr31,#REG_PC)  ,gr21 | 
 | 	ldi		@(gr31,#REG_TBR) ,gr20 | 
 |  | 
 | 	sethi.p		%hi(__debug_status),gr6 | 
 | 	setlo		%lo(__debug_status),gr6 | 
 | 	ldi.p		@(gr6,#DEBUG_DCR) ,gr6 | 
 |  | 
 | 	andi		gr22,#PSR_S,gr19		/* rebuild BPSR */ | 
 | 	andi.p		gr22,#PSR_ET,gr5 | 
 | 	slli		gr19,#10,gr19 | 
 | 	or		gr5,gr19,gr19 | 
 |  | 
 | 	movgs		gr6 ,dcr | 
 | 	movgs		gr19,bpsr | 
 | 	movgs		gr20,tbr | 
 | 	movgs		gr21,bpcsr | 
 | 	movgs		gr23,isr | 
 | 	movgs		gr24,ccr | 
 | 	movgs		gr25,cccr | 
 | 	movgs		gr26,lr | 
 | 	movgs		gr27,lcr | 
 |  | 
 | 	LEDS		0x407f,gr2 | 
 |  | 
 | #ifdef CONFIG_MMU | 
 | 	ldi		@(gr31,#REG_GR(31)),gr2 | 
 | 	movgs		gr2,scr3 | 
 | #endif | 
 |  | 
 | 	ldi		@(gr31,#REG_GR(30)),gr30 | 
 | 	ldi		@(gr31,#REG_GR(29)),gr29 | 
 | 	lddi		@(gr31,#REG_GR(26)),gr26 | 
 | 	lddi		@(gr31,#REG_GR(24)),gr24 | 
 | 	lddi		@(gr31,#REG_GR(22)),gr22 | 
 | 	lddi		@(gr31,#REG_GR(20)),gr20 | 
 | 	lddi		@(gr31,#REG_GR(18)),gr18 | 
 | 	lddi		@(gr31,#REG_GR(16)),gr16 | 
 | 	lddi		@(gr31,#REG_GR(14)),gr14 | 
 | 	lddi		@(gr31,#REG_GR(12)),gr12 | 
 | 	lddi		@(gr31,#REG_GR(10)),gr10 | 
 | 	lddi		@(gr31,#REG_GR(8)) ,gr8 | 
 | 	lddi		@(gr31,#REG_GR(6)) ,gr6 | 
 | 	lddi		@(gr31,#REG_GR(4)) ,gr4 | 
 | 	lddi		@(gr31,#REG_GR(2)) ,gr2 | 
 | 	ldi.p		@(gr31,#REG_SP)    ,sp | 
 |  | 
 | 	xor		gr31,gr31,gr31 | 
 | 	movgs		gr0,brr | 
 | #ifdef CONFIG_MMU | 
 | 	movsg		scr3,gr31 | 
 | #endif | 
 | 	rett		#1 | 
 |  | 
 | ################################################################################################### | 
 | # | 
 | # GDB stub "system calls" | 
 | # | 
 | ################################################################################################### | 
 |  | 
 | #ifdef CONFIG_GDBSTUB | 
 | 	# void gdbstub_console_write(struct console *con, const char *p, unsigned n) | 
 | 	.globl		gdbstub_console_write | 
 | gdbstub_console_write: | 
 | 	break | 
 | 	bralr | 
 | #endif | 
 |  | 
 | 	# GDB stub BUG() trap | 
 | 	# GR8 is the proposed signal number | 
 | 	.globl		__debug_bug_trap | 
 | __debug_bug_trap: | 
 | 	break | 
 | 	bralr | 
 |  | 
 | 	# transfer kernel exeception to GDB for handling | 
 | 	.globl		__break_hijack_kernel_event | 
 | __break_hijack_kernel_event: | 
 | 	break | 
 | 	.globl		__break_hijack_kernel_event_breaks_here | 
 | __break_hijack_kernel_event_breaks_here: | 
 | 	nop | 
 |  | 
 | #ifdef CONFIG_MMU | 
 | 	# handle a return from TLB-miss that requires single-step reactivation | 
 | 	.globl		__break_tlb_miss_return_break | 
 | __break_tlb_miss_return_break: | 
 | 	break | 
 | __break_tlb_miss_return_breaks_here: | 
 | 	nop | 
 | #endif | 
 |  | 
 | 	# guard the first .text label in the next file from confusion | 
 | 	nop |