123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- /*
- * Copyright (C) 2004 Axis Communications AB
- *
- * Code for handling break 8, hardware breakpoint, single step, and serial
- * port exceptions for kernel debugging purposes.
- */
- #include <hwregs/intr_vect.h>
- ;; Exported functions.
- .globl kgdb_handle_exception
- kgdb_handle_exception:
- ;; Create a register image of the caller.
- ;;
- ;; First of all, save the ACR on the stack since we need it for address calculations.
- ;; We put it into the register struct later.
- subq 4, $sp
- move.d $acr, [$sp]
- ;; Now we are free to use ACR all we want.
- ;; If we were running this handler with interrupts on, we would have to be careful
- ;; to save and restore CCS manually, but since we aren't we treat it like every other
- ;; register.
- move.d reg, $acr
- move.d $r0, [$acr] ; Save R0 (start of register struct)
- addq 4, $acr
- move.d $r1, [$acr] ; Save R1
- addq 4, $acr
- move.d $r2, [$acr] ; Save R2
- addq 4, $acr
- move.d $r3, [$acr] ; Save R3
- addq 4, $acr
- move.d $r4, [$acr] ; Save R4
- addq 4, $acr
- move.d $r5, [$acr] ; Save R5
- addq 4, $acr
- move.d $r6, [$acr] ; Save R6
- addq 4, $acr
- move.d $r7, [$acr] ; Save R7
- addq 4, $acr
- move.d $r8, [$acr] ; Save R8
- addq 4, $acr
- move.d $r9, [$acr] ; Save R9
- addq 4, $acr
- move.d $r10, [$acr] ; Save R10
- addq 4, $acr
- move.d $r11, [$acr] ; Save R11
- addq 4, $acr
- move.d $r12, [$acr] ; Save R12
- addq 4, $acr
- move.d $r13, [$acr] ; Save R13
- addq 4, $acr
- move.d $sp, [$acr] ; Save SP (R14)
- addq 4, $acr
- ;; The ACR register is already saved on the stack, so pop it from there.
- move.d [$sp],$r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $bz, [$acr]
- addq 1, $acr
- move $vr, [$acr]
- addq 1, $acr
- move $pid, [$acr]
- addq 4, $acr
- move $srs, [$acr]
- addq 1, $acr
- move $wz, [$acr]
- addq 2, $acr
- move $exs, [$acr]
- addq 4, $acr
- move $eda, [$acr]
- addq 4, $acr
- move $mof, [$acr]
- addq 4, $acr
- move $dz, [$acr]
- addq 4, $acr
- move $ebp, [$acr]
- addq 4, $acr
- move $erp, [$acr]
- addq 4, $acr
- move $srp, [$acr]
- addq 4, $acr
- move $nrp, [$acr]
- addq 4, $acr
- move $ccs, [$acr]
- addq 4, $acr
- move $usp, [$acr]
- addq 4, $acr
- move $spc, [$acr]
- addq 4, $acr
- ;; Skip the pseudo-PC.
- addq 4, $acr
- ;; Save the support registers in bank 0 - 3.
- clear.d $r1 ; Bank counter
- move.d sreg, $acr
- ;; Bank 0
- move $r1, $srs
- nop
- nop
- nop
- move $s0, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s1, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s2, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s3, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s4, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s5, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s6, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s7, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s8, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s9, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s10, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s11, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s12, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- ;; Nothing in S13 - S15, bank 0
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- ;; Bank 1 and bank 2 have the same layout, hence the loop.
- addq 1, $r1
- 1:
- move $r1, $srs
- nop
- nop
- nop
- move $s0, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s1, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s2, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s3, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s4, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s5, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s6, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- ;; Nothing in S7 - S15, bank 1 and 2
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- clear.d [$acr]
- addq 4, $acr
- addq 1, $r1
- cmpq 3, $r1
- bne 1b
- nop
- ;; Bank 3
- move $r1, $srs
- nop
- nop
- nop
- move $s0, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s1, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s2, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s3, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s4, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s5, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s6, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s7, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s8, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s9, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s10, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s11, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s12, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s13, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- move $s14, $r0
- move.d $r0, [$acr]
- addq 4, $acr
- ;; Nothing in S15, bank 3
- clear.d [$acr]
- addq 4, $acr
- ;; Check what got us here: get IDX field of EXS.
- move $exs, $r10
- and.d 0xff00, $r10
- lsrq 8, $r10
- #if defined(CONFIG_ETRAX_KGDB_PORT0)
- cmp.d SER0_INTR_VECT, $r10 ; IRQ for serial port 0
- beq sigint
- nop
- #elif defined(CONFIG_ETRAX_KGDB_PORT1)
- cmp.d SER1_INTR_VECT, $r10 ; IRQ for serial port 1
- beq sigint
- nop
- #elif defined(CONFIG_ETRAX_KGDB_PORT2)
- cmp.d SER2_INTR_VECT, $r10 ; IRQ for serial port 2
- beq sigint
- nop
- #elif defined(CONFIG_ETRAX_KGDB_PORT3)
- cmp.d SER3_INTR_VECT, $r10 ; IRQ for serial port 3
- beq sigint
- nop
- #endif
- ;; Multiple interrupt must be due to serial break.
- cmp.d 0x30, $r10 ; Multiple interrupt
- beq sigint
- nop
- ;; Neither of those? Then it's a sigtrap.
- ba handle_comm
- moveq 5, $r10 ; Set SIGTRAP (delay slot)
- sigint:
- ;; Serial interrupt; get character
- jsr getDebugChar
- nop ; Delay slot
- cmp.b 3, $r10 ; \003 (Ctrl-C)?
- bne return ; No, get out of here
- nop
- moveq 2, $r10 ; Set SIGINT
- ;;
- ;; Handle the communication
- ;;
- handle_comm:
- move.d internal_stack+1020, $sp ; Use the internal stack which grows upwards
- jsr handle_exception ; Interactive routine
- nop
- ;;
- ;; Return to the caller
- ;;
- return:
- ;; First of all, write the support registers.
- clear.d $r1 ; Bank counter
- move.d sreg, $acr
- ;; Bank 0
- move $r1, $srs
- nop
- nop
- nop
- move.d [$acr], $r0
- move $r0, $s0
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s1
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s2
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s3
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s4
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s5
- addq 4, $acr
- ;; Nothing in S6 - S7, bank 0.
- addq 4, $acr
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s8
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s9
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s10
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s11
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s12
- addq 4, $acr
- ;; Nothing in S13 - S15, bank 0
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- ;; Bank 1 and bank 2 have the same layout, hence the loop.
- addq 1, $r1
- 2:
- move $r1, $srs
- nop
- nop
- nop
- move.d [$acr], $r0
- move $r0, $s0
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s1
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s2
- addq 4, $acr
- ;; S3 (MM_CAUSE) is read-only.
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s4
- addq 4, $acr
- ;; FIXME: Actually write S5/S6? (Affects MM_CAUSE.)
- addq 4, $acr
- addq 4, $acr
- ;; Nothing in S7 - S15, bank 1 and 2
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 4, $acr
- addq 1, $r1
- cmpq 3, $r1
- bne 2b
- nop
- ;; Bank 3
- move $r1, $srs
- nop
- nop
- nop
- move.d [$acr], $r0
- move $r0, $s0
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s1
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s2
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s3
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s4
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s5
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s6
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s7
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s8
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s9
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s10
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s11
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s12
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s13
- addq 4, $acr
- move.d [$acr], $r0
- move $r0, $s14
- addq 4, $acr
- ;; Nothing in S15, bank 3
- addq 4, $acr
- ;; Now, move on to the regular register restoration process.
- move.d reg, $acr ; Reset ACR to point at the beginning of the register image
- move.d [$acr], $r0 ; Restore R0
- addq 4, $acr
- move.d [$acr], $r1 ; Restore R1
- addq 4, $acr
- move.d [$acr], $r2 ; Restore R2
- addq 4, $acr
- move.d [$acr], $r3 ; Restore R3
- addq 4, $acr
- move.d [$acr], $r4 ; Restore R4
- addq 4, $acr
- move.d [$acr], $r5 ; Restore R5
- addq 4, $acr
- move.d [$acr], $r6 ; Restore R6
- addq 4, $acr
- move.d [$acr], $r7 ; Restore R7
- addq 4, $acr
- move.d [$acr], $r8 ; Restore R8
- addq 4, $acr
- move.d [$acr], $r9 ; Restore R9
- addq 4, $acr
- move.d [$acr], $r10 ; Restore R10
- addq 4, $acr
- move.d [$acr], $r11 ; Restore R11
- addq 4, $acr
- move.d [$acr], $r12 ; Restore R12
- addq 4, $acr
- move.d [$acr], $r13 ; Restore R13
- ;;
- ;; We restore all registers, even though some of them probably haven't changed.
- ;;
- addq 4, $acr
- move.d [$acr], $sp ; Restore SP (R14)
- ;; ACR cannot be restored just yet.
- addq 8, $acr
- ;; Skip BZ, VR.
- addq 2, $acr
- move [$acr], $pid ; Restore PID
- addq 4, $acr
- move [$acr], $srs ; Restore SRS
- nop
- nop
- nop
- addq 1, $acr
- ;; Skip WZ.
- addq 2, $acr
- move [$acr], $exs ; Restore EXS.
- addq 4, $acr
- move [$acr], $eda ; Restore EDA.
- addq 4, $acr
- move [$acr], $mof ; Restore MOF.
- ;; Skip DZ.
- addq 8, $acr
- move [$acr], $ebp ; Restore EBP.
- addq 4, $acr
- move [$acr], $erp ; Restore ERP.
- addq 4, $acr
- move [$acr], $srp ; Restore SRP.
- addq 4, $acr
- move [$acr], $nrp ; Restore NRP.
- addq 4, $acr
- move [$acr], $ccs ; Restore CCS like an ordinary register.
- addq 4, $acr
- move [$acr], $usp ; Restore USP
- addq 4, $acr
- move [$acr], $spc ; Restore SPC
- ; No restoration of pseudo-PC of course.
- move.d reg, $acr ; Reset ACR to point at the beginning of the register image
- add.d 15*4, $acr
- move.d [$acr], $acr ; Finally, restore ACR.
- rete ; Same as jump ERP
- rfe ; Shifts CCS
|