793 lines
20 KiB
ArmAsm
793 lines
20 KiB
ArmAsm
|
/* 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
|