dabort.s
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:67k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. ;
  2. ; Copyright (c) 2001. Samsung Electronics, co. ltd  All rights reserved.
  3. ;
  4. ;
  5. ; Use of this source code is subject to the terms of the Microsoft end-user
  6. ; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
  7. ; If you did not accept the terms of the EULA, you are not authorized to use
  8. ; this source code. For a copy of the EULA, please see the LICENSE.RTF on your
  9. ; install media.
  10. ;
  11. ; -*-Asm-*-
  12. ;
  13. ; $Revision: 1.2 $
  14. ;   $Author: kwelton $
  15. ;     $Date: 1999/10/25 21:40:54 $
  16. ;
  17. ; dabort.s - Data abort veneer
  18. ;
  19. ; Copyright (c) 1997 ARM Limited.
  20. ; All rights reserved.
  21. ;
  22. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  23. ;
  24. ; Definitions that do not depend on assembly-time options
  25. ; =======================================================
  26. ;
  27. ; Error- and warning-related: the following are used as the first
  28. ; parameter to the INFO directive.
  29. WARNING         EQU     0
  30. ERROR           EQU     4
  31. ; Verbatim vertical bars in source text can cause problems in symbolic
  32. ; manipulations, due to their interactions with $-introduced symbol
  33. ; substitutions. To avoid this problem, we define a string variable
  34. ; here containing a vertical bar, which we will use instead of a
  35. ; literal vertical bar in most places.
  36.                 GBLS    VBar
  37. VBar            SETS    "|"
  38. ; The following definition is to get around some rather over-
  39. ; enthusiastic assembler error messages. (For maximum future-proofing,
  40. ; it should really be set to "_fsxc", but the assembler objects to
  41. ; this at present...)
  42.                 GBLS    all_fields
  43. all_fields      SETS    "_fc"
  44. ; ARM register numbers declared in such a way as to make code of the
  45. ; form R$ArithVar work.
  46. R00000000       RN      R0
  47. R00000001       RN      R1
  48. R00000002       RN      R2
  49. R00000003       RN      R3
  50. R00000004       RN      R4
  51. R00000005       RN      R5
  52. R00000006       RN      R6
  53. R00000007       RN      R7
  54. R00000008       RN      R8
  55. R00000009       RN      R9
  56. R0000000A       RN      R10
  57. R0000000B       RN      R11
  58. R0000000C       RN      R12
  59. R0000000D       RN      R13
  60. R0000000E       RN      R14
  61. R0000000F       RN      R15
  62. ; ARM PSR bits
  63. I_bit           EQU     0x80
  64. T_bit           EQU     0x20
  65. ; ARM processor mode numbers
  66. Mode_User       EQU     0x10
  67. Mode_Supervisor EQU     0x13
  68. Mode_Abort      EQU     0x17
  69. Mode_Undef      EQU     0x1B
  70. Mode_System     EQU     0x1F
  71. Mode_FullMask   EQU     0x1F    ; Mask to isolate full mode number
  72. Mode_MainMask   EQU     0x0F    ; Mask to isolate non-26/32 mode no.
  73. ; ARM PC offsets.
  74. PCOffset_DAbort EQU     8       ; R14_abort - address(aborting instr)
  75. PCOffset_Undef  EQU     4       ; R14_undef - address(undefined instr)
  76. ; ARM instruction bits. The "M bit" is one that conveniently
  77. ; distinguishes multiple transfers from single transfers for the
  78. ; purpose of the "early aborts" model and other purposes.
  79. ARM_M_bit       EQU     0x08000000      ;Multiple vs. single transfer
  80. ARM_P_bit       EQU     0x01000000      ;Pre- vs. post-indexing
  81. ARM_U_bit       EQU     0x00800000      ;Down vs. up
  82. ARM_S_bit       EQU     0x00400000      ;S bit in LDM/STM
  83. ARM_W_bit       EQU     0x00200000      ;Writeback vs. no writeback
  84. ARM_L_bit       EQU     0x00100000      ;Load vs. store
  85. ; ARM instruction fields.
  86. ARM_Rn_pos      EQU     16
  87. ARM_Rn_mask     EQU     0xF :SHL: ARM_Rn_pos
  88. ARM_Rd_pos      EQU     12
  89. ARM_Rd_mask     EQU     0xF :SHL: ARM_Rd_pos
  90. ARM_Rm_pos      EQU     0
  91. ARM_Rm_mask     EQU     0xF :SHL: ARM_Rm_pos
  92. ; Thumb instruction fields
  93. Thumb_unusual_reg_pos   EQU     8
  94. Thumb_unusual_reg_mask  EQU     0x7 :SHL: Thumb_unusual_reg_pos
  95. Thumb_usual_Rm_pos      EQU     6
  96. Thumb_usual_Rm_mask     EQU     0x7 :SHL: Thumb_usual_Rm_pos
  97. Thumb_usual_Rn_pos      EQU     3
  98. Thumb_usual_Rn_mask     EQU     0x7 :SHL: Thumb_usual_Rn_pos
  99. Thumb_usual_Rd_pos      EQU     0
  100. Thumb_usual_Rd_mask     EQU     0x7 :SHL: Thumb_usual_Rd_pos
  101. Thumb_Imm5_pos          EQU     6
  102. Thumb_Imm5_mask         EQU     0x1F :SHL: Thumb_Imm5_pos
  103. Thumb_Imm8_pos          EQU     0
  104. Thumb_Imm8_mask         EQU     0xFF :SHL: Thumb_Imm8_pos
  105. Thumb_L_bit             EQU     0x0800
  106. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  107. ;
  108. ; Processing of assembly-time options
  109. ; ===================================
  110. ;
  111. ; The following code supplies default values for assembly-time
  112. ; options, checks for illegal or meaningless combinations, etc.
  113. ;
  114. ; * 'VeneerEntry' is mandatory, and will be treated as a label. We
  115. ;    reprocess it at this stage to ensure that it is surrounded by
  116. ;    vertical bars. (These clean-ups and similar ones later are *not*
  117. ;    intended to catch all possible syntactic errors - just to allow
  118. ;    the symbol to be specified with or without the vertical bars and
  119. ;    to catch the most obvious syntactic errors.)
  120.         [ :LNOT::DEF:VeneerEntry
  121.                 GBLS    VeneerEntry
  122. VeneerEntry     SETS    ""
  123.         ]
  124.         [ VeneerEntry = ""
  125.                 INFO    ERROR, 
  126.                         "'VeneerEntry' has not been defined."
  127.         ]
  128.         [ ((VeneerEntry:LEFT:1) = VBar) 
  129.           :LEOR: ((VeneerEntry:RIGHT:1) = VBar)
  130.                 INFO    ERROR, 
  131.                         "Vertical bar error in 'VeneerEntry'"
  132.         ]
  133.         [ (VeneerEntry:LEFT:1) <> VBar
  134. VeneerEntry     SETS    VBar:CC:VeneerEntry:CC:VBar
  135.         ]
  136. ; * 'AreaName' is optional, defaulting to "DataAbortVeneerCode". (Done
  137. ;    via an empty string to also catch cases where it has been defined
  138. ;    as the empty string.) It gets the usual vertical bar
  139. ;    reprocessing.
  140.         [ :LNOT::DEF:AreaName
  141.                 GBLS    AreaName
  142. AreaName        SETS    ""
  143.         ]
  144.         [ AreaName = ""
  145. AreaName        SETS    "DataAbortVeneerCode"
  146.         ]
  147.         [ ((AreaName:LEFT:1) = VBar) 
  148.           :LEOR: ((AreaName:RIGHT:1) = VBar)
  149.                 INFO    ERROR, 
  150.                         "Vertical bar error in 'AreaName'"
  151.         ]
  152.         [ (AreaName:LEFT:1) <> VBar
  153. AreaName        SETS    VBar:CC:AreaName:CC:VBar
  154.         ]
  155. ; * 'BaseUpdated', 'BaseRestored' and 'EarlyAbort' are each optional,
  156. ;   defaulting to {FALSE}. However, at least one of them must be
  157. ;   {TRUE}, and we're interested in how many are {TRUE} for the
  158. ;   purpose of determining whether we are supporting multiple abort
  159. ;   models.
  160.         [ :LNOT::DEF:BaseUpdated
  161.                 GBLL    BaseUpdated
  162. BaseUpdated     SETL    {FALSE}
  163.         ]
  164.         [ :LNOT::DEF:BaseRestored
  165.                 GBLL    BaseRestored
  166. BaseRestored    SETL    {FALSE}
  167.         ]
  168.         [ :LNOT::DEF:EarlyAbort
  169.                 GBLL    EarlyAbort
  170. EarlyAbort      SETL    {FALSE}
  171.         ]
  172.                 GBLA    AbortModelCount
  173. AbortModelCount SETA    0
  174.         [ BaseUpdated
  175. AbortModelCount SETA    AbortModelCount+1
  176.         ]
  177.         [ BaseRestored
  178. AbortModelCount SETA    AbortModelCount+1
  179.         ]
  180.         [ EarlyAbort
  181. AbortModelCount SETA    AbortModelCount+1
  182.         ]
  183.         [ AbortModelCount = 0
  184.                 INFO    ERROR, 
  185.                         "Must specify at least one abort model."
  186.         ]
  187. ; * 'AbortModelVar' and 'AbortModelInit' can both default to the empty
  188. ;   string regardless of the number of abort models supported. (In the
  189. ;   case of 'AbortModelVar', this empty string will later generate an
  190. ;   error if more than 1 abort model is specified.)
  191. ;     If more than one abort model is specified, 'AbortModelVar' is
  192. ;   mandatory.
  193.         [ :LNOT::DEF:AbortModelVar
  194.                 GBLS    AbortModelVar
  195. AbortModelVar   SETS    ""
  196.         ]
  197.         [ :LNOT::DEF:AbortModelInit
  198.                 GBLS    AbortModelInit
  199. AbortModelInit  SETS    ""
  200.         ]
  201.         [ (AbortModelCount > 1) :LAND: (AbortModelVar = "")
  202.                 INFO    ERROR, 
  203.                         "'AbortModelVar' has not been defined."
  204.         ]
  205.         [ AbortModelVar <> ""
  206.           [ ((AbortModelVar:LEFT:1) = VBar) 
  207.             :LEOR: ((AbortModelVar:RIGHT:1) = VBar)
  208.                 INFO    ERROR, 
  209.                         "Vertical bar error in 'AbortModelVar'."
  210.           ]
  211.           [ (AbortModelVar:LEFT:1) <> VBar
  212. AbortModelVar   SETS    VBar:CC:AbortModelVar:CC:VBar
  213.           ]
  214.         ]
  215.         [ AbortModelInit <> ""
  216.           [ AbortModelVar = ""
  217.                 INFO    ERROR, 
  218.                         "'AbortModelInit' without 'AbortModelVar'."
  219.           ]
  220.           [ ((AbortModelInit:LEFT:1) = VBar) 
  221.             :LEOR: ((AbortModelInit:RIGHT:1) = VBar)
  222.                 INFO    ERROR, 
  223.                         "Vertical bar error in 'AbortModelInit'."
  224.           ]
  225.           [ (AbortModelInit:LEFT:1) <> VBar
  226. AbortModelInit  SETS    VBar:CC:AbortModelInit:CC:VBar
  227.           ]
  228.         ]
  229. ; * 'HandlerCallStd' defaults to "APCS_NOSWST".
  230.         [ :LNOT::DEF:HandlerCallStd
  231.                 GBLS    HandlerCallStd
  232. HandlerCallStd  SETS    ""
  233.         ]
  234.         [ HandlerCallStd = ""
  235. HandlerCallStd  SETS    "APCS_NOSWST"
  236.         ]
  237.                 GBLL    CallStdKnown
  238. CallStdKnown    SETL    {FALSE}
  239.                 GBLL    CallStdHasLabel
  240. CallStdHasLabel SETL    {FALSE}
  241.         [ HandlerCallStd = "APCS_NOSWST"
  242. CallStdKnown    SETL    {TRUE}
  243. CallStdHasLabel SETL    {TRUE}
  244.         ]
  245.         [ HandlerCallStd = "APCS_SWST"
  246. CallStdKnown    SETL    {TRUE}
  247. CallStdHasLabel SETL    {TRUE}
  248.         ]
  249.         [ HandlerCallStd = "APCS_MACRO"
  250. CallStdKnown    SETL    {TRUE}
  251.         ]
  252.         [ :LNOT:CallStdKnown
  253.                 INFO    ERROR, 
  254.                         "Unknown 'HandlerCallStd' requested"
  255.         ]
  256. ; * 'HandlerName' is mandatory, and undergoes the usual vertical bar
  257. ;   clean-ups if it is to be treated as a label.
  258.         [ :LNOT::DEF:HandlerName
  259.                 GBLS    HandlerName
  260. HandlerName     SETS    ""
  261.         ]
  262.         [ HandlerName = ""
  263.                 INFO    ERROR, 
  264.                         "'HandlerName' has not been defined."
  265.         ]
  266.         [ CallStdHasLabel
  267.           [ ((HandlerName:LEFT:1) = VBar) 
  268.             :LEOR: ((HandlerName:RIGHT:1) = VBar)
  269.                 INFO    ERROR, 
  270.                         "Vertical bar error in 'HandlerName'"
  271.           ]
  272.           [ (HandlerName:LEFT:1) <> VBar
  273. HandlerName     SETS    VBar:CC:HandlerName:CC:VBar
  274.           ]
  275.         ]
  276. ; * 'HandlerCallMode' defaults to "Supervisor" or "Abort", depending
  277. ;   on the procedure calling standard used, and has three legal values
  278. ;   - which we also translate here to mode numbers.
  279.         [ :LNOT::DEF:HandlerCallMode
  280.                 GBLS    HandlerCallMode
  281. HandlerCallMode SETS    ""
  282.         ]
  283.         [ HandlerCallMode = ""
  284.           [ HandlerCallStd = "APCS_MACRO"
  285. HandlerCallMode SETS    "Abort"
  286.           |
  287. HandlerCallMode SETS    "Supervisor"
  288.           ]
  289.         ]
  290.                 GBLL    CallModeKnown
  291. CallModeKnown   SETL    {FALSE}
  292.         [ HandlerCallMode = "Supervisor"
  293. CallModeKnown   SETL    {TRUE}
  294. Mode_Callee     EQU     Mode_Supervisor
  295.         ]
  296.         [ HandlerCallMode = "System"
  297. CallModeKnown   SETL    {TRUE}
  298. Mode_Callee     EQU     Mode_System
  299.         ]
  300.         [ HandlerCallMode = "Abort"
  301. CallModeKnown   SETL    {TRUE}
  302. Mode_Callee     EQU     Mode_Abort
  303.         ]
  304.         [ :LNOT:CallModeKnown
  305.                 INFO    ERROR, 
  306.                         "Unknown 'HandlerCallMode' requested"
  307.         ]
  308. ; * The stack limit variable specified by "HandlerSL" is mandatory for
  309. ;   the "APCS_SWST" procedure calling standard, unnecessary and unused
  310. ;   otherwise.
  311.         [ :LNOT::DEF:HandlerSL
  312.                 GBLS    HandlerSL
  313. HandlerSL       SETS    ""
  314.         ]
  315.         [ HandlerCallStd = "APCS_SWST"
  316.           [ HandlerSL = ""
  317.                 INFO    ERROR, 
  318.                         "'HandlerSL' has not been specified."
  319.           ]
  320.           [ ((HandlerSL:LEFT:1) = VBar) 
  321.             :LEOR: ((HandlerSL:RIGHT:1) = VBar)
  322.                 INFO    ERROR, 
  323.                         "Vertical bar error in 'HandlerSL'"
  324.           ]
  325.           [ (HandlerSL:LEFT:1) <> VBar
  326. HandlerSL       SETS    VBar:CC:HandlerSL:CC:VBar
  327.           ]
  328.         |
  329.           [ HandlerSL <> ""
  330.                 INFO    WARNING, 
  331.                         "'HandlerSL' will not be used."
  332.           ]
  333.         ]
  334. ; * The parameter-passing options 'PassSPSR', 'PassInstrAddr',
  335. ;   'PassRegDumpAddr' and 'PassXferAddr' all default to {FALSE}.
  336.         [ :LNOT::DEF:PassSPSR
  337.                 GBLL    PassSPSR
  338. PassSPSR        SETL    {FALSE}
  339.         ]
  340.         [ :LNOT::DEF:PassInstrAddr
  341.                 GBLL    PassInstrAddr
  342. PassInstrAddr   SETL    {FALSE}
  343.         ]
  344.         [ :LNOT::DEF:PassRegDumpAddr
  345.                 GBLL    PassRegDumpAddr
  346. PassRegDumpAddr SETL    {FALSE}
  347.         ]
  348.         [ :LNOT::DEF:PassXferAddr
  349.                 GBLL    PassXferAddr
  350. PassXferAddr    SETL    {FALSE}
  351.         ]
  352. ; * The 'allowed return values' options all default to not allowing
  353. ;   the return value, but some must be specified, including at least
  354. ;   one that is legitimate when an error occurs.
  355.         [ :LNOT::DEF:ReturnNormal
  356.                 GBLL    ReturnNormal
  357. ReturnNormal    SETL    {FALSE}
  358.         ]
  359.         [ :LNOT::DEF:ReturnUndef
  360.                 GBLS    ReturnUndef
  361. ReturnUndef     SETS    ""
  362.         ]
  363.         [ (ReturnUndef <> "") :LAND: ((ReturnUndef:LEFT:2) <> "0x")
  364.           [ ((ReturnUndef:LEFT:1) = VBar) 
  365.             :LEOR: ((ReturnUndef:RIGHT:1) = VBar)
  366.                 INFO    ERROR, 
  367.                         "Vertical bar error in 'ReturnUndef'"
  368.           ]
  369.           [ (ReturnUndef:LEFT:1) <> VBar
  370. ReturnUndef     SETS    VBar:CC:ReturnUndef:CC:VBar
  371.           ]
  372.         ]
  373.         [ :LNOT::DEF:ReturnToNext
  374.                 GBLS    ReturnToNext
  375. ReturnToNext    SETS    ""
  376.         ]
  377.         [ ReturnToNext <> ""
  378.           [ ((ReturnToNext:LEFT:1) = VBar) 
  379.             :LEOR: ((ReturnToNext:RIGHT:1) = VBar)
  380.                 INFO    ERROR, 
  381.                         "Vertical bar error in 'ReturnToNext'"
  382.           ]
  383.           [ (ReturnToNext:LEFT:1) <> VBar
  384. ReturnToNext    SETS    VBar:CC:ReturnToNext:CC:VBar
  385.           ]
  386.         ]
  387.         [ :LNOT::DEF:ReturnAddress
  388.                 GBLL    ReturnAddress
  389. ReturnAddress   SETL    {FALSE}
  390.         ]
  391.         [ (ReturnUndef = "") :LAND: (:LNOT:ReturnAddress)
  392.                 INFO    ERROR, 
  393.                         "No legitimate return value for errors."
  394.         ]
  395. ; * 'SuptThumb' defaults to {TRUE}.
  396.         [ :LNOT::DEF:SuptThumb
  397.                 GBLL    SuptThumb
  398. SuptThumb       SETL    {TRUE}
  399.         ]
  400. ; * 'StrictErrors' defaults to {TRUE}.
  401.         [ :LNOT::DEF:StrictErrors
  402.                 GBLL    StrictErrors
  403. StrictErrors    SETL    {TRUE}
  404.         ]
  405. ; * The defined-but-not-implemented options 'SuptBaseEqIndex' and
  406. ;   'SuptLoadBaseWB' get their default values, with errors/warnings if
  407. ;   the as-yet-unsupported option is chosen.
  408.         [ :LNOT::DEF:SuptBaseEqIndex
  409.                 GBLL    SuptBaseEqIndex
  410. SuptBaseEqIndex SETL    {FALSE}
  411.         ]
  412.         [ SuptBaseEqIndex
  413.                 INFO    ERROR, 
  414.                         "'SuptBaseEqIndex' option not yet implemented"
  415.         ]
  416.         [ :LNOT::DEF:SuptLoadBaseWB
  417.                 GBLL    SuptLoadBaseWB
  418. SuptLoadBaseWB  SETL    {FALSE}
  419.         ]
  420.         [ SuptLoadBaseWB
  421.                 INFO    ERROR, 
  422.                         "'SuptLoadBaseWB' option not yet implemented"
  423.         ]
  424. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  425. ;
  426. ; Definitions that depend on assembly-time options
  427. ; ================================================
  428. ;
  429. ; The following macro does the final stages of the call to the
  430. ; OS-specific handler.
  431.                 MACRO
  432. $label          HandlerInternalMacro
  433.                 ALIGN
  434. $label
  435.         [ HandlerCallStd = "APCS_MACRO"
  436.                 $HandlerName
  437.         |
  438.           [ HandlerCallStd = "APCS_SWST"
  439.                 LDR     R10, =$HandlerSL
  440.           ]
  441.                 IMPORT  $HandlerName
  442.                 BL      $HandlerName
  443.         ]
  444.                 MEND
  445. ; Specific return values allowed from OS-specific handler. These
  446. ; definitions are made dependent on the relevant assembly-time option
  447. ; in order to catch coding errors.
  448.         [ ReturnNormal
  449. DABORT_RETVAL_NORMAL    EQU     0x0
  450.         ]
  451.         [ ReturnUndef <> ""
  452. DABORT_RETVAL_UNDEF     EQU     0x4
  453.         ]
  454.         [ ReturnToNext <> ""
  455. DABORT_RETVAL_TONEXT    EQU     0x10
  456.         ]
  457. ; Error codes.
  458. DABORT_ERROR_BAD_REQUEST        EQU     -1
  459. DABORT_ERROR_NONE               EQU     0
  460. DABORT_ERROR_BASEEQINDEX_PRE    EQU     1
  461. DABORT_ERROR_BASEEQINDEX_POST   EQU     2
  462. DABORT_ERROR_R15_WB             EQU     3
  463. DABORT_ERROR_BASE_R15           EQU     4
  464. DABORT_ERROR_INDEX_R15          EQU     5
  465. DABORT_ERROR_LOAD_WB            EQU     6
  466. DABORT_ERROR_LDMSTM_EMPTY       EQU     7
  467. DABORT_ERROR_USERBANK_WB        EQU     8
  468. DABORT_ERROR_BAD_INSTR          EQU     9
  469. ; Abort models.
  470.         [ BaseRestored
  471. DABORT_MODEL_BASERESTORED       EQU     0
  472.         ]
  473.         [ EarlyAbort
  474. DABORT_MODEL_EARLYABORT         EQU     1
  475.         ]
  476.         [ BaseUpdated
  477. DABORT_MODEL_BASEUPDATED        EQU     3
  478.         ]
  479.         [ AbortModelInit <> ""
  480. DABORT_MODEL_INITIALISATION     EQU     0x40000000      ; And higher
  481.         ]
  482. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  483. ;
  484. ; Start of generated code
  485. ; =======================
  486. ;
  487. ; Start by declaring the area.
  488.                 AREA    $AreaName, CODE
  489. ; The main entry point
  490. ; ====================
  491. $VeneerEntry
  492.                 EXPORT  $VeneerEntry
  493. ; First thing the code must do is set up its register dump. This has
  494. ; to be done carefully, to ensure that the correct mode's registers
  495. ; are stored. We start by reserving the right amount of space and
  496. ; dumping the unbanked registers, to give ourselves some space to work
  497. ; in. We also get the return link and SPSR into callee-saved registers
  498. ; at this point, adjusting the return link to point to the aborting
  499. ; instruction in the process.
  500.                 SUB     R13, R13, #15*4
  501.                 STMIA   R13, {R0-R7}
  502.                 SUB     R4, R14, #PCOffset_DAbort
  503.                 MRS     R5, SPSR
  504. ; Now do the rest of the registers. This usually involves switching to
  505. ; the mode concerned (or strictly speaking, to its 32-bit equivalent),
  506. ; dumping the registers and switching back. However, if the mode
  507. ; concerned is a user mode, we must instead use a "user bank" STM, to
  508. ; avoid getting trapped in user mode.
  509.                 ADD     R0, R13, #8*4   ; Place to dump registers
  510.                 ANDS    R1, R5, #Mode_MainMask
  511.                 ASSERT  (Mode_User:AND:Mode_MainMask) = 0
  512.                 STMEQIA R0, {R8-R14}^
  513.                 BEQ     RegsDumped
  514.                 MRS     R2, CPSR
  515.                 BIC     R3, R2, #Mode_MainMask
  516.                 ORR     R1, R3, R1
  517.                 MSR     CPSR$all_fields, R1
  518.                 STMIA   R0, {R8-R14}
  519.                 MSR     CPSR$all_fields, R2
  520. RegsDumped
  521. ; *** Live register values at this point are:
  522. ;     R4:  Pointer to aborting instruction
  523. ;     R5:  SPSR value
  524. ;     R13: Stack pointer (pointing to register dump)
  525. ;
  526. ; Find out what abort model we're using (if relevant) and initialise
  527. ; the error code.
  528.         [ AbortModelVar <> ""
  529.                 IMPORT  $AbortModelVar
  530.                 LDR     R6, =$AbortModelVar
  531.                 LDR     R8, [R6]
  532.           [ AbortModelInit <> ""
  533.                 CMP     R8, #DABORT_MODEL_INITIALISATION
  534.                 BHS     Initialisation_Handler
  535.           ]
  536.         ]
  537.                 MOV     R6, #DABORT_ERROR_NONE
  538. ; We need to obtain and analyse the aborting instruction in any of the
  539. ; following circumstances:
  540. ;
  541. ; * If "StrictErrors" is set.
  542. ;
  543. ; * If we're expected to pass the instruction's transfer address as a
  544. ;   parameter to the OS-specific handler.
  545. ;
  546. ; * If we're dealing with anything other than the Base Restored Abort
  547. ;   Model.
  548.         [ StrictErrors 
  549.           :LOR: PassXferAddr 
  550.           :LOR: (:LNOT:BaseRestored) 
  551.           :LOR: (AbortModelCount > 1)
  552.           [ (:LNOT:StrictErrors) 
  553.             :LAND: (:LNOT:PassXferAddr) 
  554.             :LAND: BaseRestored
  555.                 ASSERT  AbortModelVar <> ""     ; So R8 was loaded
  556.                 CMP     R8, #DABORT_MODEL_BASERESTORED
  557.                 BEQ     CallOSHandlerWithError
  558.           ]
  559.           [ SuptThumb
  560. ; Test for whether the instruction is a Thumb instruction, and branch
  561. ; off to separate code to handle it if so.
  562.                 TST     R5, #T_bit
  563.                 BNE     ThumbInstruction
  564.           ]
  565. ARMInstruction
  566. ; ARM instruction analysis
  567. ; ========================
  568. ;
  569. ; Get the instruction. We can use a normal LDR instruction to do this,
  570. ; not an LDRT, even if we were invoked from user mode, because:
  571. ;
  572. ; * The fact that a data abort occurred on the offending instruction,
  573. ;   not a prefetch abort, indicates that the instruction was
  574. ;   accessible from user mode.
  575. ;
  576. ; * User mode programs cannot fake a data abort vector entry in order
  577. ;   to create a security loophole. (They can branch to location 0x10,
  578. ;   but cannot also get into a privileged mode unless they take the
  579. ;   data abort trap.)
  580.                 LDR     R0, [R4]
  581. ; *** Live register values at this point are:
  582. ;     R0:  Aborting instruction
  583. ;     R4:  Pointer to aborting instruction
  584. ;     R5:  SPSR value
  585. ;     R6:  Error code
  586. ;     R8:  Abort model (if relevant)
  587. ;     R13: Stack pointer (pointing to register dump)
  588. ;
  589. ; Now start analysing the instruction. The objective of this stage is
  590. ; to end up with:
  591. ;
  592. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  593. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  594. ;          U bit (bit 23) indicating whether indexing is up or down.
  595. ;          W bit (bit 21) indicating whether base register writeback
  596. ;            is required.
  597. ;          L bit (bit 20) indicating whether a load or a store, at least
  598. ;            when writeback is involved or there is a potential "user bank"
  599. ;            LDM.
  600. ;     R1:  Number of base register, still in instruction position.
  601. ;     R2:  Offset value.
  602. ;     R3:  Number of destination register, still in instruction
  603. ;          position (for all but LDM/STM/LDC/STC).
  604. ;
  605. ; In many cases, R0 will be the unchanged instruction; however, it
  606. ; does get changed in some circumstances to "standardise" the meanings
  607. ; of the bits.
  608. ;
  609. ; R1 and R3 are particularly simple, since the base register field is
  610. ; in the same position for all ARM load/store instructions, and the
  611. ; destination field is in the same position for all single load
  612. ; instructions.
  613.                 AND     R1, R0, #ARM_Rn_mask
  614.                 AND     R3, R0, #ARM_Rd_mask
  615. ; Now split according to the major class of the instruction - i.e.
  616. ; bits 27:25.
  617.                 AND     R2, R0, #(0x7:SHL:25)
  618.                 ADD     PC, PC, R2, LSR #23
  619.                 NOP                             ;Branch table padding
  620.                 B       ARM_Odds_And_Ends       ;SWP, LDRH, etc.
  621.                 B       ARM_Should_Not_Happen   ;(Data processing)
  622.                 B       ARM_LDR_STR_Immed
  623.                 B       ARM_LDR_STR_Reg
  624.                 B       ARM_LDM_STM
  625.                 B       ARM_Should_Not_Happen   ;(B/BL)
  626.                 B       ARM_LDC_STC
  627. ARM_Should_Not_Happen                           ;(CDP/MRC/MCR/SWI)
  628.                 MOV     R6, #DABORT_ERROR_BAD_INSTR
  629.                 B       CallOSHandlerWithError
  630. ; Analysis of ARM SWP/SWPB/LDRH/LDRSB/LDRSH/STRH instructions
  631. ; -----------------------------------------------------------
  632. ;
  633. ; Start by distinguishing SWP instructions from the rest.
  634. ARM_Odds_And_Ends
  635.                 TST     R0, #0x3 :SHL: 5
  636.                 BNE     ARM_LDRH_etc
  637. ; Analysis of ARM SWP/SWPB instructions
  638. ; -------------------------------------
  639. ;
  640. ; This will behave like a pre-indexed instruction with an offset of 0
  641. ; and no writeback - i.e. P=1, U=don't care, W=0. SWP/SWPB
  642. ; instructions should already be like this, and it is an error if they
  643. ; are not.
  644. ARM_SWP
  645.                 AND     R7, R0, #ARM_P_bit + ARM_W_bit
  646.                 CMP     R7, #ARM_P_bit
  647.                 BNE     ARM_Should_Not_Happen
  648. ; A base register of R15 is also an error.
  649.                 CMP     R1, #0xF :SHL: ARM_Rn_pos
  650.                 MOVEQ   R6, #DABORT_ERROR_BASE_R15
  651.                 BEQ     CallOSHandlerWithError
  652. ; Set an offset of 0 and continue.
  653.                 MOV     R2, #0          ;Set offset of 0
  654.                 B       RegisterAdjust
  655. ; Analysis of ARM LDRH/LDRSB/LDRSH/STRH instructions
  656. ; --------------------------------------------------
  657. ;
  658. ; First thing is to force writeback to be set if post-indexed; then
  659. ; split into immediate and register forms.
  660. ARM_LDRH_etc
  661.                 TST     R0, #ARM_P_bit
  662.                 ORREQ   R0, R0, #ARM_W_bit
  663.                 TST     R0, #ARM_S_bit
  664.                 BEQ     ARM_LDRH_etc_Reg
  665. ARM_LDRH_etc_Immed
  666. ; We just have to generate the correct offset.
  667.                 AND     R2, R0, #0xF
  668.                 AND     R7, R0, #0xF00
  669.                 ORR     R2, R2, R7, LSR #4
  670.                 B       RegisterAdjust
  671. ARM_LDRH_etc_Reg
  672. ; There are a number of errors to detect:
  673. ;
  674. ; * An index register of R15.
  675.                 AND     R2, R0, #ARM_Rm_mask
  676.                 CMP     R2, #0xF :SHL: ARM_Rm_pos
  677.                 MOVEQ   R6, #DABORT_ERROR_INDEX_R15
  678.                 BEQ     CallOSHandlerWithError
  679. ; * Base register = index register, with writeback.
  680.                 CMP     R2, R1, LSR #(ARM_Rn_pos - ARM_Rm_pos)
  681.                 BNE     ARM_LDRH_etc_Reg_OK
  682.                 TST     R0, #ARM_W_bit
  683.                 BNE     ARM_LDR_STR_Reg_NotOK   ;To shared error code
  684. ARM_LDRH_etc_Reg_OK
  685. ; Get the index register value and go to common code.
  686.                 LDR     R2, [R13, R2, LSL #(2 - ARM_Rm_pos)]
  687.                 B       RegisterAdjust
  688. ; Analysis of ARM LDC/STC instructions
  689. ; ------------------------------------
  690. ;
  691. ; Offset comes direct from the instruction. M, P, U, W and L bits are
  692. ; already right.
  693. ARM_LDC_STC
  694.                 AND     R2, R0, #0xFF
  695.                 MOV     R2, R2, LSL #2
  696.                 B       RegisterAdjust2 ;Avoid "load and w/back" check
  697. ; Analysis of ARM LDM/STM instructions
  698. ; ------------------------------------
  699. ;
  700. ; Offset is implied by number of set bits in register mask; M, U, W
  701. ; and L bits are set correctly. P bit cannot be set in a manner that
  702. ; corresponds properly to the other instructions, so this case doesn't
  703. ; share all of the standard "RegisterAdjust" code.
  704. ARM_LDM_STM
  705. ; Need to check for some error conditions:
  706. ;
  707. ; * Base register of R15.
  708.                 CMP     R1, #0xF :SHL: ARM_Rn_pos
  709.                 MOVEQ   R6, #DABORT_ERROR_BASE_R15
  710.                 BEQ     CallOSHandlerWithError
  711. ; * Register mask empty. (Calculate register mask at the same time and
  712. ;   put it into top end of R3.)
  713.                 MOVS    R3, R0, LSL #16         ;Isolate register mask
  714.                 MOVEQ   R6, #DABORT_ERROR_LDMSTM_EMPTY
  715.                 BEQ     CallOSHandlerWithError
  716. ; * Writeback and load of same register.
  717.                 TST     R0, #ARM_W_bit          ;Writeback?
  718.                 TSTNE   R0, #ARM_L_bit          ;And a load?
  719.                 MOVNE   R7, R1, LSR #ARM_Rn_pos
  720.                 MOVNE   R7, R3, LSR R7
  721.                 TSTNE   R7, #0x10000            ;And base in list?
  722.                 MOVNE   R6, #DABORT_ERROR_LOAD_WB
  723.                 BNE     CallOSHandlerWithError
  724. ; * Writeback in user bank form.
  725.                 TST     R0, #ARM_W_bit          ;Writeback?
  726.                 TSTNE   R0, #ARM_S_bit          ;Potentially user bank?
  727.                 BEQ     ARM_LDM_STM_OK
  728.                 TST     R3, #0x10000 :SHL: 15   ;Is it loading R15?
  729.                 TSTNE   R0, #ARM_L_bit          ;And a load?
  730.                 MOVEQ   R6, #DABORT_ERROR_USERBANK_WB
  731.                 BEQ     CallOSHandlerWithError
  732. ARM_LDM_STM_OK
  733. ; *** Live register values at this point are:
  734. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  735. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  736. ;          U bit (bit 23) indicating whether indexing is up or down.
  737. ;          W bit (bit 21) indicating whether base register writeback
  738. ;            is required.
  739. ;     R1:  Number of base register, still in instruction position.
  740. ;     R3:  Register list mask (only the number of set bits matters).
  741. ;     R4:  Pointer to aborting instruction
  742. ;     R5:  SPSR value
  743. ;     R6:  Error code
  744. ;     R8:  Abort model (if relevant)
  745. ;     R13: Stack pointer (pointing to register dump)
  746. ;
  747. ; Calculate offset from mask, by repeatedly isolating and removing the
  748. ; least significant bit in the mask until it is zero. Note we know the
  749. ; mask is non-zero.
  750.                 MOV     R2, #0
  751. ARM_LDM_STM_OffsetLoop
  752.                 ADD     R2, R2, #4
  753.                 RSB     R7, R3, #0      ;Unequal above lowest 1, equal
  754.                                         ; at lowest 1 and below
  755.                 BICS    R3, R3, R7      ;So this clears lowest 1
  756.                 BNE     ARM_LDM_STM_OffsetLoop
  757.         [ PassXferAddr
  758. ; We need to know what the difference between the transfer address and
  759. ; the (possibly corrected) base address is. This is given by the
  760. ; following table:
  761. ;
  762. ;   P bit  U bit  Addressing mode  Transfer address - base address
  763. ;   --------------------------------------------------------------
  764. ;     0      0         DA           4 - R2
  765. ;     0      1         IA           0
  766. ;     1      0         DB           -R2
  767. ;     1      1         IB           4
  768. ;
  769. ; The following code puts the appropriate value in R3.
  770.                 TST     R0, #ARM_P_bit
  771.                 MOVEQ   R3, #4
  772.                 MOVNE   R3, #0
  773.                 TST     R0, #ARM_U_bit
  774.                 SUBEQ   R3, R3, R2
  775.                 RSBNE   R3, R3, #4
  776.         ]
  777.                 B       RegisterAdjust3
  778. ; Analysis of ARM LDR/STR instructions with register offset
  779. ; ---------------------------------------------------------
  780. ;
  781. ; Offset is Rm, shifted appropriately; force writeback if
  782. ; post-indexed. M, P, U and L bits are already right.
  783. ARM_LDR_STR_Reg
  784.                 TST     R0, #ARM_P_bit
  785.                 ORREQ   R0, R0, #ARM_W_bit
  786.                 AND     R2, R0, #ARM_Rm_mask
  787. ; Need to check for some error conditions:
  788. ;
  789. ; * An invalid instruction.
  790.                 TST     R0, #0x00000010
  791.                 BNE     ARM_Should_Not_Happen
  792. ; * An index register of R15.
  793.                 CMP     R2, #0xF :SHL: ARM_Rm_pos
  794.                 MOVEQ   R6, #DABORT_ERROR_INDEX_R15
  795.                 BEQ     CallOSHandlerWithError
  796. ; * Base register = index register, with writeback.
  797.                 CMP     R2, R1, LSR #(ARM_Rn_pos - ARM_Rm_pos)
  798.                 BNE     ARM_LDR_STR_Reg_OK
  799.                 TST     R0, #ARM_W_bit
  800.                 BNE     ARM_LDR_STR_Reg_NotOK
  801. ARM_LDR_STR_Reg_OK
  802. ; Get the index register value.
  803.                 LDR     R2, [R13, R2, LSL #(2 - ARM_Rm_pos)]
  804. ; Now we need to apply the shift. Split according to the shift type.
  805.                 AND     R7, R0, #3 :SHL: 5
  806.                 ADD     PC, PC, R7, LSR #3
  807.                 NOP                             ;Branch table padding
  808.                 B       ARM_LDR_STR_Reg_LSL
  809.                 B       ARM_LDR_STR_Reg_LSR
  810.                 B       ARM_LDR_STR_Reg_ASR
  811. ARM_LDR_STR_Reg_ROR
  812.                 ANDS    R7, R0, #0x1F :SHL: 7
  813.                 MOVNE   R7, R7, LSR #7          ;If amount non-zero,
  814.                 MOVNE   R2, R2, ROR R7          ; ROR correctly
  815.                 BNE     RegisterAdjust
  816. ; We've got an RRX shift. This has got to be silly, but it's just as
  817. ; easy to handle it correctly as to produce an error.
  818.                 MOVS    R7, R5, LSL #3          ;Caller's C -> C
  819.                 MOV     R2, R2, RRX
  820.                 B       RegisterAdjust
  821. ARM_LDR_STR_Reg_ASR
  822.                 ANDS    R7, R0, #0x1F :SHL: 7
  823.                 MOVNE   R7, R7, LSR #7          ;If amount non-zero,
  824.                 MOVNE   R2, R2, ASR R7          ; ASR correctly
  825.                 MOVEQ   R2, R2, ASR #32         ;Else ASR by 32
  826.                 B       RegisterAdjust
  827. ARM_LDR_STR_Reg_LSR
  828.                 ANDS    R7, R0, #0x1F :SHL: 7
  829.                 MOVNE   R7, R7, LSR #7          ;If amount non-zero,
  830.                 MOVNE   R2, R2, LSR R7          ; LSR correctly
  831.                 MOVEQ   R2, R2, LSR #32         ;Else LSR by 32
  832.                 B       RegisterAdjust
  833. ARM_LDR_STR_Reg_LSL
  834.                 AND     R7, R0, #0x1F :SHL: 7
  835.                 MOV     R7, R7, LSR #7
  836.                 MOV     R2, R2, LSL R7
  837.                 B       RegisterAdjust
  838. ARM_LDR_STR_Reg_NotOK
  839.                 TST     R0, #ARM_P_bit
  840.                 MOVEQ   R6, #DABORT_ERROR_BASEEQINDEX_POST
  841.                 MOVNE   R6, #DABORT_ERROR_BASEEQINDEX_PRE
  842.                 B       CallOSHandlerWithError
  843. ; Analysis of ARM LDR/STR instructions with immediate offset
  844. ; ----------------------------------------------------------
  845. ;
  846. ; Offset comes direct from the instruction; force writeback if
  847. ; post-indexed. M, P, U and L bits are already right.
  848. ARM_LDR_STR_Immed
  849.                 MOV     R2, R0, LSL #20
  850.                 MOV     R2, R2, LSR #20
  851.                 TST     R0, #ARM_P_bit
  852.                 ORREQ   R0, R0, #ARM_W_bit
  853. ; Fall through to RegisterAdjust if following code isn't assembled.
  854.           [ SuptThumb
  855.                 B       RegisterAdjust
  856.                 LTORG
  857. ThumbInstruction
  858. ; Thumb instruction analysis
  859. ; ==========================
  860. ;
  861. ; Get the instruction. We can use a normal LDRH instruction to do this,
  862. ; rather than faking an "LDRHT" from an LDRT, for the same reasons that we
  863. ; can use LDR rather than LDRT to fetch an ARM instruction - see "ARM
  864. ; instruction analysis" above.
  865.                 LDRH    R0, [R4]
  866. ; *** Live register values at this point are:
  867. ;     R0:  Aborting instruction
  868. ;     R4:  Pointer to aborting instruction
  869. ;     R5:  SPSR value
  870. ;     R6:  Error code
  871. ;     R8:  Abort model (if relevant)
  872. ;     R13: Stack pointer (pointing to register dump)
  873. ;
  874. ; Now start analysing the instruction. The objective of this stage is
  875. ; to end up with the same register contents as the ARM instruction analysis,
  876. ; i.e.:
  877. ;
  878. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  879. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  880. ;          U bit (bit 23) indicating whether indexing is up or down.
  881. ;          W bit (bit 21) indicating whether base register writeback
  882. ;            is required.
  883. ;          [ L bit (bit 20) indicating whether a load or a store, at least
  884. ;            when writeback is involved or there is a potential "user bank"
  885. ;            LDM. Not needed in general for Thumb instructions - the
  886. ;            writebacks for LDM/POP/PUSH/STM will be dealt with specially. ]
  887. ;     R1:  Number of base register, in ARM instruction position.
  888. ;     R2:  Offset value.
  889. ;     R3:  Number of destination register, in ARM instruction position
  890. ;          (for all but LDM/POP/PUSH/STM).
  891. ;
  892. ; Unlike the ARM instruction case, we will have to do a lot of "faking" to
  893. ; get things right. We do at least have the advantage that all the relevant
  894. ; bits of R0 are known to be zero at this point.
  895. ;
  896. ; Set R1 and R3 from the most usual positions of the base and destination
  897. ; registers in Thumb instructions.
  898.                 AND     R1, R0, #Thumb_usual_Rn_mask
  899.                 MOV     R1, R1, LSL #(ARM_Rn_pos - Thumb_usual_Rn_pos)
  900.                 AND     R3, R0, #Thumb_usual_Rd_mask
  901.                 MOV     R3, R3, LSL #(ARM_Rd_pos - Thumb_usual_Rd_pos)
  902. ; Now split according to the major class of the instruction - i.e.
  903. ; bits 15:12.
  904.                 AND     R2, R0, #(0xF:SHL:12)
  905.                 ADD     PC, PC, R2, LSR #10
  906.                 NOP                             ;Branch table padding
  907.                 B       ARM_Should_Not_Happen   ;(Shift imm.)
  908.                 B       ARM_Should_Not_Happen   ;(Shift imm., add/sub)
  909.                 B       ARM_Should_Not_Happen   ;(Add/sub/compare/move
  910.                 B       ARM_Should_Not_Happen   ; immediate)
  911.                 B       Thumb_PCbased           ;(Also data processing)
  912.                 B       Thumb_RegOffset
  913.                 B       Thumb_LDR_STR
  914.                 B       Thumb_LDRB_STRB
  915.                 B       Thumb_LDRH_STRH
  916.                 B       Thumb_SPbased
  917.                 B       ARM_Should_Not_Happen   ;(ADR from PC/SP)
  918.                 B       Thumb_PUSH_POP          ;(Also SP adjust/Undef)
  919.                 B       Thumb_LDM_STM
  920.                 B       ARM_Should_Not_Happen   ;(Bcc/SWI/Undef)
  921.                 B       ARM_Should_Not_Happen   ;(Uncond. branch/Undef)
  922.                 B       ARM_Should_Not_Happen   ;(BL high/low)
  923. ; Analysis of Thumb PC-based PUSH/POP instructions
  924. ; ------------------------------------------------
  925. Thumb_PUSH_POP
  926. ; Checks for errors:
  927. ;
  928. ; * Instruction not in fact PUSH/POP:
  929.                 TST     R0, #0x0400
  930.                 BEQ     ARM_Should_Not_Happen
  931. ; * Empty register mask - register mask gets calculated at the same
  932. ;   time and put in R3. Note that only the number of set bits in the
  933. ;   register mask matters, so we don't have to shift the LR/PC bit to
  934. ;   the correct position.
  935.                 BICS    R3, R0, #0xFE00
  936.                 MOVEQ   R6, #DABORT_ERROR_LDMSTM_EMPTY
  937.                 BEQ     CallOSHandlerWithError
  938. ; We will branch into the ARM LDM/STM code at the point where all
  939. ; error checks have been performed. Things we still need to do are:
  940. ;
  941. ; * Set the M, P, U and W bits correctly in R0 (1/0/1/1 for POP,
  942. ;   1/1/0/1 for PUSH).
  943. ; * Set R1 to the correct base register number (R13).
  944.                 BIC     R3, R0, #0xFE00
  945.                 MOV     R1, #(0xD :SHL: ARM_Rn_pos)
  946.                 TST     R0, #Thumb_L_bit
  947.                 ORREQ   R0, R0, #ARM_M_bit + ARM_P_bit + ARM_W_bit
  948.                 ORRNE   R0, R0, #ARM_M_bit + ARM_U_bit + ARM_W_bit
  949.                 B       ARM_LDM_STM_OK
  950. ; Analysis of Thumb PC-based LDM/STM instructions
  951. ; -----------------------------------------------
  952. Thumb_LDM_STM
  953. ; Checks for errors:
  954. ; * Empty register mask - register mask gets calculated at the same
  955. ;   time and put in R3.
  956.                 BICS    R3, R0, #0xFF00
  957.                 MOVEQ   R6, #DABORT_ERROR_LDMSTM_EMPTY
  958.                 BEQ     CallOSHandlerWithError
  959. ; * Writeback and load of the same register. We've definitely got
  960. ;   writeback, so it's just a question of whether the base register
  961. ;   appears in the register list. First, get the base register number
  962. ;   into R1 and put it into ARM base register position (where it is
  963. ;   needed later anyway). Then check whether it appears in the
  964. ;   register list.
  965.                 AND     R1, R0, #Thumb_unusual_reg_mask
  966.                 MOV     R1, R1, LSL #(ARM_Rn_pos - Thumb_unusual_reg_pos)
  967.                 MOV     R7, R1, LSR #ARM_Rn_pos
  968.                 MOV     R7, R3, LSR R7
  969.                 TST     R7, #1
  970.                 MOVNE   R6, #DABORT_ERROR_LOAD_WB
  971.                 BNE     CallOSHandlerWithError
  972. ; We will branch into the ARM LDM/STM code at the point where all
  973. ; error checks have been performed. The only thing we still need to do
  974. ; is set the M, P, U and W bits correctly in R0 (1/0/1/1 for both LDM
  975. ; and STM).
  976.                 ORR     R0, R0, #ARM_M_bit + ARM_U_bit + ARM_W_bit
  977.                 B       ARM_LDM_STM_OK
  978. ; Analysis of Thumb LDRx/STRx with register offset
  979. ; ------------------------------------------------
  980. ;
  981. ; R0 bits should be M=0, P=1, U=1, W=0. R1 and R3 are right; R2 value
  982. ; should be obtained from the Thumb instruction's Rm field. There are
  983. ; no problems with an index register of R15 or with writeback with
  984. ; index = base, since the Thumb instruction doesn't permit a "high"
  985. ; index register or base register writeback.
  986. Thumb_RegOffset
  987.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  988.                 AND     R2, R0, #Thumb_usual_Rm_mask
  989.                 LDR     R2, [R13, R2, LSR #(Thumb_usual_Rm_pos - 2)]
  990.                 B       RegisterAdjust
  991. ; Analysis of Thumb SP-based LDR/STR
  992. ; ----------------------------------
  993. ;
  994. ; R0 bits should be M=0, P=1, U=1, W=0. R1 should indicate R13. R3
  995. ; should be calculated from the variant Rd position used for this
  996. ; instruction. Finally, the offset is extracted from the instruction
  997. ; and shifted into "times 4" position.
  998. Thumb_SPbased
  999.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  1000.                 MOV     R1, #(0xD :SHL: ARM_Rn_pos)
  1001.                 AND     R3, R0, #Thumb_unusual_reg_mask
  1002.                 MOV     R3, R3, LSL #(ARM_Rd_pos - Thumb_unusual_reg_pos)
  1003.                 AND     R2, R0, #Thumb_Imm8_mask
  1004.                 MOV     R2, R2, LSL #(2 - Thumb_Imm8_pos)
  1005.                 B       RegisterAdjust
  1006. ; Analysis of Thumb PC-based LDR
  1007. ; ------------------------------
  1008. Thumb_PCbased
  1009. ; Check instruction is right (not the data processing instructions
  1010. ; with the same major opcode, which look like PC-based STRs).
  1011.                 TST     R0, #Thumb_L_bit
  1012.                 BEQ     ARM_Should_Not_Happen
  1013. ; R0 bits should be M=0, P=1, U=1, W=0. R1 should indicate R15; the
  1014. ; "RegisterAdjust" code below will apply the appropriate
  1015. ; Thumb-specific modifications to it. R3 should be calculated from the
  1016. ; variant Rd position used for this instruction. Finally, the offset
  1017. ; is extracted from the instruction and shifted into "times 4"
  1018. ; position.
  1019.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  1020.                 MOV     R1, #(0xF :SHL: ARM_Rn_pos)
  1021.                 AND     R3, R0, #Thumb_unusual_reg_mask
  1022.                 MOV     R3, R3, LSL #(ARM_Rd_pos - Thumb_unusual_reg_pos)
  1023.                 AND     R2, R0, #Thumb_Imm8_mask
  1024.                 MOV     R2, R2, LSL #(2 - Thumb_Imm8_pos)
  1025.                 B       RegisterAdjust
  1026. ; Analysis of Thumb LDR/STR with immediate offset
  1027. ; -----------------------------------------------
  1028. ;
  1029. ; R1 and R3 values are already correct; R0 bits should be M=0, P=1,
  1030. ; U=1, W=0; offset needs to be extracted from the instruction and
  1031. ; shifted into "times 4" position.
  1032. Thumb_LDR_STR
  1033.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  1034.                 AND     R2, R0, #Thumb_Imm5_mask
  1035.                 MOV     R2, R2, LSR #(Thumb_Imm5_pos - 2)
  1036.                 B       RegisterAdjust
  1037. ; Analysis of Thumb LDRB/STRB with immediate offset
  1038. ; -------------------------------------------------
  1039. ;
  1040. ; R1 and R3 values are already correct; R0 bits should be M=0, P=1,
  1041. ; U=1, W=0; offset needs to be extracted from the instruction and
  1042. ; shifted into "times 1" position.
  1043. Thumb_LDRB_STRB
  1044.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  1045.                 AND     R2, R0, #Thumb_Imm5_mask
  1046.                 MOV     R2, R2, LSR #(Thumb_Imm5_pos - 0)
  1047.                 B       RegisterAdjust
  1048. ; Analysis of Thumb LDRH/STRH with immediate offset
  1049. ; -------------------------------------------------
  1050. ;
  1051. ; R1 and R3 values are already correct; R0 bits should be M=0, P=1,
  1052. ; U=1, W=0; offset needs to be extracted from the instruction and
  1053. ; shifted into "times 2" position.
  1054. Thumb_LDRH_STRH
  1055.                 ORR     R0, R0, #ARM_P_bit + ARM_U_bit
  1056.                 AND     R2, R0, #Thumb_Imm5_mask
  1057.                 MOV     R2, R2, LSR #(Thumb_Imm5_pos - 1)
  1058. ; Fall through to RegisterAdjust.
  1059.           ] ; of SuptThumb section
  1060. RegisterAdjust
  1061. ; *** Live register values at this point are:
  1062. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  1063. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  1064. ;          U bit (bit 23) indicating whether indexing is up or down.
  1065. ;          W bit (bit 21) indicating whether base register writeback
  1066. ;            is required.
  1067. ;          L bit (bit 20) indicating whether a load or a store, at
  1068. ;            least when writeback is occurring.
  1069. ;     R1:  Number of base register, still in ARM instruction position.
  1070. ;     R2:  Offset value.
  1071. ;     R3:  Number of destination register, still in ARM instruction
  1072. ;          position.
  1073. ;     R4:  Pointer to aborting instruction
  1074. ;     R5:  SPSR value
  1075. ;     R6:  Error code
  1076. ;     R8:  Abort model (if relevant)
  1077. ;     R13: Stack pointer (pointing to register dump)
  1078. ;
  1079. ; This code is shared between all instructions except LDM/STMs and
  1080. ; LDCs/STCs. First, check for the "Load and write back to same
  1081. ; register" case.
  1082.                 CMP     R3, R1, LSR #(ARM_Rn_pos - ARM_Rd_pos)
  1083.                 BNE     RegisterAdjust2
  1084.                 TST     R0, #ARM_W_bit
  1085.                 TSTNE   R0, #ARM_L_bit
  1086.                 MOVNE   R6, #DABORT_ERROR_LOAD_WB
  1087.                 BNE     CallOSHandlerWithError
  1088. RegisterAdjust2
  1089. ; *** Live register values at this point are:
  1090. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  1091. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  1092. ;          U bit (bit 23) indicating whether indexing is up or down.
  1093. ;          W bit (bit 21) indicating whether base register writeback
  1094. ;            is required.
  1095. ;     R1:  Number of base register, still in ARM instruction position.
  1096. ;     R2:  Offset value.
  1097. ;     R4:  Pointer to aborting instruction
  1098. ;     R5:  SPSR value
  1099. ;     R6:  Error code
  1100. ;     R8:  Abort model (if relevant)
  1101. ;     R13: Stack pointer (pointing to register dump)
  1102. ;
  1103. ; If we're required to produce the transfer address, calculate the
  1104. ; offset from the base address (after it has been corrected) to the
  1105. ; transfer address.
  1106.           [ PassXferAddr
  1107.                 TST     R0, #ARM_U_bit
  1108.                 MOVNE   R3, R2
  1109.                 RSBEQ   R3, R2, #0
  1110.                 TST     R0, #ARM_P_bit
  1111.                 MOVEQ   R3, #0
  1112.           ]
  1113. RegisterAdjust3
  1114. ; *** Live register values at this point are:
  1115. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  1116. ;          P bit (bit 24) indicating pre- vs. post-indexing.
  1117. ;          U bit (bit 23) indicating whether indexing is up or down.
  1118. ;          W bit (bit 21) indicating whether base register writeback
  1119. ;            is required.
  1120. ;     R1:  Number of base register, still in ARM instruction position.
  1121. ;     R2:  Offset value.
  1122. ;     R3:  Transfer address - base address (if "PassXferAddr"
  1123. ;          specified).
  1124. ;     R4:  Pointer to aborting instruction
  1125. ;     R5:  SPSR value
  1126. ;     R6:  Error code
  1127. ;     R8:  Abort model (if relevant)
  1128. ;     R13: Stack pointer (pointing to register dump)
  1129. ;
  1130. ; There is one more error to check for, namely use of a base register
  1131. ; of R15 with writeback. We will get hold of the base register value
  1132. ; at the same time, as it happens to be convenient to use the R15 test
  1133. ; for that purpose as well.
  1134.                 CMP     R1, #0xF :SHL: ARM_Rn_pos
  1135.                 LDRNE   R7, [R13, R1, LSR #(ARM_Rn_pos - 2)]
  1136.                 BNE     RegisterAdjust4
  1137.                 TST     R0, #ARM_W_bit
  1138.                 MOVNE   R6, #DABORT_ERROR_R15_WB
  1139.                 BNE     CallOSHandlerWithError
  1140. ; Add correct offset to instruction pointer to get the right R15 base
  1141. ; value. For Thumb, the only PC-based load/store instruction also
  1142. ; clears bit 1.
  1143.                 ADD     R7, R4, #8
  1144.         [ SuptThumb
  1145.                 TST     R5, #T_bit
  1146.                 ADDNE   R7, R4, #4
  1147.                 BICNE   R7, R7, #2
  1148.         ]
  1149. RegisterAdjust4
  1150. ; *** Live register values at this point are:
  1151. ;     R0:  M bit (bit 27) indicating multiple vs. single transfer.
  1152. ;          U bit (bit 23) indicating whether indexing is up or down.
  1153. ;          W bit (bit 21) indicating whether base register writeback
  1154. ;            is required.
  1155. ;     R1:  Number of base register, still in ARM instruction position.
  1156. ;     R2:  Offset value.
  1157. ;     R3:  Transfer address - base address (if "PassXferAddr"
  1158. ;          specified).
  1159. ;     R4:  Pointer to aborting instruction
  1160. ;     R5:  SPSR value
  1161. ;     R6:  Error code
  1162. ;     R7:  Value of base register
  1163. ;     R8:  Abort model (if relevant)
  1164. ;     R13: Stack pointer (pointing to register dump)
  1165. ;
  1166. ; We're finally ready to do base register restoration if required. The
  1167. ; rules here are:
  1168. ;
  1169. ; * If we've got just a single abort model, follow its dictates about
  1170. ;   base register restoration.
  1171. ;
  1172. ; * Otherwise, use the appropriate bit of the abort model number in R8.
  1173.           [ AbortModelCount = 1
  1174.             [ BaseRestored
  1175.                 ; Fall through (next chunk of code won't be assembled).
  1176.             ]
  1177.             [ BaseUpdated
  1178.                 ; Fall through
  1179.             ]
  1180.             [ EarlyAbort
  1181.                 TST     R0, #ARM_M_bit
  1182.                 BEQ     CallOSHandlerNoError
  1183.             ]
  1184.           |
  1185.                 TST     R0, #ARM_M_bit
  1186.                 MOVEQ   R8, R8, LSR #1
  1187.                 TST     R8, #1
  1188.                 BEQ     CallOSHandlerNoError
  1189.           ]
  1190.           [ :LNOT:((AbortModelCount = 1) :LAND: BaseRestored)
  1191. ; If we get here, we need to restore the base register value
  1192. ; appropriately, provided it has actually been written back.
  1193.                 TST     R0, #ARM_W_bit
  1194.                 BEQ     CallOSHandlerNoError
  1195.                 TST     R0, #ARM_U_bit
  1196.                 ADDEQ   R7, R7, R2      ;Add if originally subtracted
  1197.                 SUBNE   R7, R7, R2      ; and vice versa
  1198.                 STR     R7, [R13, R1, LSR #(ARM_Rn_pos - 2)]
  1199.           ]
  1200. CallOSHandlerNoError
  1201.           [ PassXferAddr
  1202. ; Produce transfer address from corrected base address and previously
  1203. ; calculated difference.
  1204.                 ADD     R7, R7, R3
  1205.           ]
  1206.         ] ; of complex condition saying whether to analyse instruction
  1207. CallOSHandlerWithError
  1208. ; OS-specific handler call
  1209. ; ========================
  1210. ;
  1211. ; *** Live register values at this point are:
  1212. ;     R4:  Pointer to aborting instruction
  1213. ;     R5:  SPSR value
  1214. ;     R6:  Error code
  1215. ;     R7:  Transfer address (if wanted & relevant; otherwise junk)
  1216. ;     R13: Stack pointer (pointing to register dump)
  1217. ;
  1218. ; Switch into the correct mode (if necessary) - but first we may need
  1219. ; to put the register dump pointer somewhere safe. R8 is a suitable
  1220. ; callee-save register.
  1221.         [ PassRegDumpAddr :LOR: (HandlerCallMode <> "Abort")
  1222.                 MOV     R8, R13
  1223.         ]
  1224.         [ HandlerCallMode <> "Abort"
  1225.                 MRS     R3, CPSR
  1226.                 BIC     R3, R3, #Mode_FullMask
  1227.                 ORR     R3, R3, #Mode_Callee
  1228.                 MSR     CPSR$all_fields, R3
  1229.         ]
  1230. ; Marshall the arguments required. This uses some rather messy
  1231. ; conditional assembly, the idea of which is to marshall the arguments
  1232. ; in reverse order in R0-R3, dumping partial lists to the stack. First
  1233. ; count the arguments.
  1234.                 GBLA    ArgCount
  1235. ArgCount        SETA    1
  1236.         [ PassSPSR
  1237. ArgCount        SETA    ArgCount+1
  1238.         ]
  1239.         [ PassInstrAddr
  1240. ArgCount        SETA    ArgCount+1
  1241.         ]
  1242.         [ PassRegDumpAddr
  1243. ArgCount        SETA    ArgCount+1
  1244.         ]
  1245.         [ PassXferAddr
  1246. ArgCount        SETA    ArgCount+1
  1247.         ]
  1248. ; Now ArgVar counts down through the arguments; ArgVar2 determines
  1249. ; which register each should go to; ArgString contains the arguments
  1250. ; not yet on the stack, each preceded by a comma (the first comma
  1251. ; needs stripping before using ArgString in an STMFD instruction.
  1252.                 GBLA    ArgVar
  1253. ArgVar          SETA    ArgCount
  1254.                 GBLA    ArgVar2
  1255.                 GBLS    ArgString
  1256. ArgString       SETS    ""
  1257.         [ PassXferAddr
  1258. ArgVar          SETA    ArgVar-1
  1259. ArgVar2         SETA    ArgVar :AND: 3
  1260. ArgString       SETS    ",R$ArgVar2" :CC: ArgString
  1261.                 MOV     R$ArgVar2, R7
  1262.           [ ArgVar2 = 0 :LAND: ArgVar <> 0
  1263. ArgString       SETS    ArgString :RIGHT: (:LEN:ArgString - 1)
  1264.                 STMFD   R13!,{$ArgString}
  1265. ArgString       SETS    ""
  1266.           ]
  1267.         ]
  1268.         [ PassRegDumpAddr
  1269. ArgVar          SETA    ArgVar-1
  1270. ArgVar2         SETA    ArgVar :AND: 3
  1271. ArgString       SETS    ",R$ArgVar2" :CC: ArgString
  1272.                 MOV     R$ArgVar2, R8
  1273.           [ ArgVar2 = 0 :LAND: ArgVar <> 0
  1274. ArgString       SETS    ArgString :RIGHT: (:LEN:ArgString - 1)
  1275.                 STMFD   R13!,{$ArgString}
  1276. ArgString       SETS    ""
  1277.           ]
  1278.         ]
  1279.         [ PassInstrAddr
  1280. ArgVar          SETA    ArgVar-1
  1281. ArgVar2         SETA    ArgVar :AND: 3
  1282. ArgString       SETS    ",R$ArgVar2" :CC: ArgString
  1283.                 MOV     R$ArgVar2, R4
  1284.           [ ArgVar2 = 0 :LAND: ArgVar <> 0
  1285. ArgString       SETS    ArgString :RIGHT: (:LEN:ArgString - 1)
  1286.                 STMFD   R13!,{$ArgString}
  1287. ArgString       SETS    ""
  1288.           ]
  1289.         ]
  1290.         [ PassSPSR
  1291. ArgVar          SETA    ArgVar-1
  1292. ArgVar2         SETA    ArgVar :AND: 3
  1293. ArgString       SETS    ",R$ArgVar2" :CC: ArgString
  1294.                 MOV     R$ArgVar2, R5
  1295.           [ ArgVar2 = 0 :LAND: ArgVar <> 0
  1296. ArgString       SETS    ArgString :RIGHT: (:LEN:ArgString - 1)
  1297.                 STMFD   R13!,{$ArgString}
  1298. ArgString       SETS    ""
  1299.           ]
  1300.         ]
  1301. ArgVar          SETA    ArgVar-1
  1302. ArgVar2         SETA    ArgVar :AND: 3
  1303. ArgString       SETS    ",R$ArgVar2" :CC: ArgString
  1304.                 MOV     R$ArgVar2, R6
  1305.           [ ArgVar2 = 0 :LAND: ArgVar <> 0
  1306. ArgString       SETS    ArgString :RIGHT: (:LEN:ArgString - 1)
  1307.                 STMFD   R13!,{$ArgString}
  1308. ArgString       SETS    ""
  1309.           ]
  1310. ; Check all the above conditional assembly is self-consistent.
  1311.                 ASSERT ArgVar = 0
  1312. ; Finally, we're ready to issue the procedure call.
  1313. ;
  1314. ; *** Live register values at this point are:
  1315. ;     R0-R3: Arguments as appropriate
  1316. ;     R4:  Pointer to aborting instruction
  1317. ;     R5:  SPSR value
  1318. ;     R6:  Error code
  1319. ;     R7:  Transfer address
  1320. ;     R8:  R13_abort value (if calling in other than abort mode)
  1321. ;     R13: Stack pointer (pointing to any arguments over four)
  1322.                 HandlerInternalMacro
  1323. ; If we needed to use some stack for the argument list, release it.
  1324.         [ ArgCount > 4
  1325.                 ADD     R13, R13, #(ArgCount-4)*4
  1326.         ]
  1327. ; If we switched modes, restore abort mode and R13_abort.
  1328.         [ HandlerCallMode <> "Abort"
  1329.                 MRS     R3, CPSR
  1330.                 BIC     R3, R3, #Mode_FullMask
  1331.                 ORR     R3, R3, #Mode_Abort
  1332.                 MSR     CPSR$all_fields, R3
  1333.                 MOV     R13, R8
  1334.         ]
  1335. ; Deal with the OS-specific handler's return value
  1336. ; ================================================
  1337.         [ ReturnNormal
  1338. ; Code to return and retry the aborting instruction
  1339. ; -------------------------------------------------
  1340. ;
  1341. ; *** Live register values at this point are:
  1342. ;     R0:  Return value from OS-specific handler
  1343. ;     R4:  Pointer to aborting instruction
  1344. ;     R5:  SPSR value
  1345. ;     R6:  Error code
  1346. ;     R13: Stack pointer (pointing to register dump)
  1347.                 CMP     R0, #DABORT_RETVAL_NORMAL
  1348.                 BNE     NotReturnNormal
  1349. ; This return value isn't valid unless there was no error originally.
  1350.                 CMP     R6, #DABORT_ERROR_NONE
  1351.                 BNE     ReturnInvalid
  1352. ; We need to take care about how we return if we're to get all the
  1353. ; registers right. First thing to do is restore the banked registers -
  1354. ; this needs the same precautions about user modes as the
  1355. ; corresponding entry code.
  1356.                 ADD     R7, R13, #8*4   ; Place to find reg values
  1357.                 ANDS    R1, R5, #Mode_MainMask
  1358.                 ASSERT  (Mode_User:AND:Mode_MainMask) = 0
  1359.                 LDMEQIA R7, {R8-R14}^
  1360.                 BEQ     RegsRestored_Normal
  1361.                 MRS     R2, CPSR
  1362.                 BIC     R3, R2, #Mode_MainMask
  1363.                 ORR     R1, R3, R1
  1364.                 MSR     CPSR$all_fields, R1
  1365.                 LDMIA   R7, {R8-R14}
  1366.                 MSR     CPSR$all_fields, R2
  1367. RegsRestored_Normal
  1368. ; PC value wanted is the address of the aborting instruction, CPSR
  1369. ; value wanted is the entry SPSR value.
  1370.                 STR     R4, [R13, #14*4]
  1371.                 MSR     SPSR$all_fields, R5
  1372. ; Now we're ready to restore the rest of the registers and return.
  1373.                 LDMIA   R13, {R0-R7}
  1374.                 ADD     R13, R13, #14*4
  1375.                 LDMIA   R13!, {PC}^
  1376.                 LTORG
  1377. NotReturnNormal
  1378.         ]
  1379.         [ ReturnUndef <> ""
  1380. ; Code to fake an undefined instruction trap
  1381. ; ------------------------------------------
  1382. ;
  1383. ; *** Live register values at this point are:
  1384. ;     R0:  Return value from OS-specific handler
  1385. ;     R4:  Pointer to aborting instruction
  1386. ;     R5:  SPSR value
  1387. ;     R6:  Error code
  1388. ;     R13: Stack pointer (pointing to register dump)
  1389.                 CMP     R0, #DABORT_RETVAL_UNDEF
  1390.                 BNE     NotReturnUndef
  1391. ; There are a number of CPSR manipulations in what follows, so get it
  1392. ; into a register. Also produce a "main mode number blanked" version
  1393. ; of it.
  1394.                 MRS     R2, CPSR
  1395.                 BIC     R3, R2, #Mode_MainMask
  1396. ; We need to take care about how we return if we're to get all the
  1397. ; registers right. First thing to do is restore the banked registers -
  1398. ; this needs the same precautions about user modes as the
  1399. ; corresponding entry code.
  1400.                 ADD     R7, R13, #8*4   ; Place to find reg values
  1401.                 ANDS    R1, R5, #Mode_MainMask
  1402.                 ASSERT  (Mode_User:AND:Mode_MainMask) = 0
  1403.                 LDMEQIA R7, {R8-R14}^
  1404.                 BEQ     RegsRestored_Undef
  1405.                 ORR     R1, R3, R1
  1406.                 MSR     CPSR$all_fields, R1
  1407.                 LDMIA   R7, {R8-R14}
  1408. ; N.B. No need to shift back to the original mode at this point.
  1409. RegsRestored_Undef
  1410. ; Next, we need to shift over to undefined instruction mode in order
  1411. ; to get R14_undef and SPSR_undef right, then shift back so that we
  1412. ; can do the rest of the work on the abort mode stack.
  1413.                 ORR     R1, R3, #Mode_Undef
  1414.                 MSR     CPSR$all_fields, R1
  1415.                 MSR     SPSR$all_fields, R5
  1416.                 ADD     R14, R4, #PCOffset_Undef
  1417.                 MSR     CPSR$all_fields, R2
  1418. ; Now put the CPSR we want to end up with in SPSR_abort, and the PC
  1419. ; value we want to end up with in the top used word of the stack.
  1420.                 BIC     R0, R5, #Mode_FullMask + T_bit
  1421.                 ORR     R0, R0, #Mode_Undef + I_bit
  1422.                 MSR     SPSR$all_fields, R0
  1423.                 LDR     R0, =$ReturnUndef
  1424.                 STR     R0, [R13, #14*4]
  1425. ; Now we're ready to finish "returning".
  1426.                 LDMIA   R13, {R0-R7}
  1427.                 ADD     R13, R13, #14*4
  1428.                 LDMIA   R13!, {PC}^
  1429.                 LTORG
  1430. NotReturnUndef
  1431.         ]
  1432.         [ ReturnToNext <> ""
  1433. ; Code to chain to a second data abort handler
  1434. ; --------------------------------------------
  1435. ;
  1436. ; *** Live register values at this point are:
  1437. ;     R0:  Return value from OS-specific handler
  1438. ;     R4:  Pointer to aborting instruction
  1439. ;     R5:  SPSR value
  1440. ;     R6:  Error code
  1441. ;     R13: Stack pointer (pointing to register dump)
  1442.                 CMP     R0, #DABORT_RETVAL_TONEXT
  1443.                 BNE     NotReturnToNext
  1444. ; This return value isn't valid unless there was no error originally.
  1445.                 CMP     R6, #DABORT_ERROR_NONE
  1446.                 BNE     ReturnInvalid
  1447. ; We need to take care about how we return if we're to get all the
  1448. ; registers right. First thing to do is restore the banked registers -
  1449. ; this needs the same precautions about user modes as the
  1450. ; corresponding entry code.
  1451.                 ADD     R7, R13, #8*4   ; Place to find reg values
  1452.                 ANDS    R1, R5, #Mode_MainMask
  1453.                 ASSERT  (Mode_User:AND:Mode_MainMask) = 0
  1454.                 LDMEQIA R7, {R8-R14}^
  1455.                 BEQ     RegsRestored_ToNext
  1456.                 MRS     R2, CPSR
  1457.                 BIC     R3, R2, #Mode_MainMask
  1458.                 ORR     R1, R3, R1
  1459.                 MSR     CPSR$all_fields, R1
  1460.                 LDMIA   R7, {R8-R14}
  1461.                 MSR     CPSR$all_fields, R2
  1462. RegsRestored_ToNext
  1463. ; Restore R14_abort, SPSR_abort and the CPSR to their entry values.
  1464.                 ADD     R14, R4, #PCOffset_DAbort
  1465.                 MSR     SPSR$all_fields, R5
  1466.                 BIC     R0, R5, #Mode_FullMask + T_bit
  1467.                 ORR     R0, R0, #Mode_Abort + I_bit
  1468.                 MSR     CPSR$all_fields, R0
  1469. ; Now put the PC value we want to end up with in the top used word of
  1470. ; the stack.
  1471.                 IMPORT  $ReturnToNext
  1472.                 LDR     R0, =$ReturnToNext
  1473.                 STR     R0, [R13, #14*4]
  1474. ; Now we're ready to finish "returning".
  1475.                 LDMIA   R13, {R0-R7}
  1476.                 ADD     R13, R13, #14*4
  1477.                 LDMIA   R13!, {PC}
  1478.                 LTORG
  1479. NotReturnToNext
  1480.         ]
  1481.         [ ReturnAddress
  1482. ; Code to transfer to the R0-specified address
  1483. ; --------------------------------------------
  1484. ;
  1485. ; *** Live register values at this point are:
  1486. ;     R0:  Return value from OS-specific handler
  1487. ;     R4:  Pointer to aborting instruction
  1488. ;     R5:  SPSR value
  1489. ;     R6:  Error code
  1490. ;     R13: Stack pointer (pointing to register dump)
  1491. ;
  1492. ; We need to take care about how we return if we're to get all the
  1493. ; registers right. First thing to do is restore the banked registers
  1494. ; to the correct mode's registers. Also set SPSR_abort to produce the
  1495. ; desired final mode, if it isn't abort mode.
  1496.                 ADD     R7, R13, #8*4   ; Place to find reg values
  1497.           [ HandlerCallMode = "Abort"
  1498.                 LDMIA   R7, {R8-R14}
  1499.           |
  1500.                 MRS     R2, CPSR
  1501.                 BIC     R1, R2, #Mode_FullMask
  1502.                 ORR     R1, R1, #Mode_Callee
  1503.                 MSR     SPSR$all_fields, R1
  1504.                 MSR     CPSR$all_fields, R1
  1505.                 LDMIA   R7, {R8-R14}
  1506.                 MSR     CPSR$all_fields, R2
  1507.           ]
  1508. ; Now put the PC value we want to end up with in the top used word of
  1509. ; the stack.
  1510.                 STR     R0, [R13, #14*4]
  1511. ; Now we're ready to finish "returning", with a mode change if
  1512. ; necessary.
  1513.                 LDMIA   R13, {R0-R7}
  1514.                 ADD     R13, R13, #14*4
  1515.           [ HandlerCallMode = "Abort"
  1516.                 LDMIA   R13!, {PC}
  1517.           |
  1518.                 LDMIA   R13!, {PC}^
  1519.           ]
  1520.                 LTORG
  1521.         ]
  1522.         [ (:LNOT:ReturnAddress) 
  1523.           :LOR: ReturnNormal 
  1524.           :LOR: (ReturnToNext <> "")
  1525. ; Code to deal with invalid requests
  1526. ; ----------------------------------
  1527. ;
  1528. ; This code can either be fallen through to (if the "ReturnAddress"
  1529. ; option isn't requested), or branched to from the "ReturnNormal" or
  1530. ; "ReturnToNext" code.
  1531. ReturnInvalid
  1532. ; *** Live register values at this point are:
  1533. ;     R0:  Return value from OS-specific handler
  1534. ;     R4:  Pointer to aborting instruction
  1535. ;     R5:  SPSR value
  1536. ;     R6:  Error code
  1537. ;     R13: Stack pointer (pointing to register dump)
  1538. ;
  1539. ; We need to issue a second call to the OS-specific handler at this
  1540. ; point, with the "bad request" error code as its first parameter. The
  1541. ; remaining parameters can be junk, so will simply be whatever happens
  1542. ; to be in the registers concerned. (Most will in fact be OK.)
  1543.                 MOV     R6, #DABORT_ERROR_BAD_REQUEST
  1544.                 B       CallOSHandlerWithError
  1545.                 LTORG
  1546.         ]
  1547.         [ AbortModelInit <> ""
  1548. Initialisation_Handler
  1549. ; Special handler for initialisation routine
  1550. ; ==========================================
  1551. ;
  1552. ; *** Live register values at this point are:
  1553. ;     
  1554. ;     R4:  Pointer to aborting instruction
  1555. ;     R5:  SPSR value
  1556. ;     R6:  Address of abort model variable
  1557. ;     R8:  Abort model variable value
  1558. ;     R13: Stack pointer (pointing to register dump)
  1559. ;
  1560. ; The abort model identifier is initialised to 0x40000000. Each entry
  1561. ; to this handler shifts the value left by one bit, shifting in a zero
  1562. ; if the base register was not changed and a 1 if it was. After two
  1563. ; such entries, the high order bit is shifted out and we should be in
  1564. ; a normal abort model. The first time round is done with an LDR
  1565. ; instruction, the second with an LDM, in order to test the behaviour
  1566. ; for both single and multiple transfers (needed to distinguish the
  1567. ; "early aborts" model).
  1568. ;   Both instructions will use R1 as their base register and will set
  1569. ; R0 to a copy of the original base register, so the test for a
  1570. ; changed base register is simply to compare the R0 and R1 values in
  1571. ; the register dump.
  1572.                 LDMIA   R13, {R0, R1}
  1573.                 MOV     R8, R8, LSL #1
  1574.                 CMP     R0, R1
  1575.                 ORRNE   R8, R8, #1
  1576.                 STR     R8, [R6]
  1577. ; Now we're ready to return. We need to take care about how we return
  1578. ; if we're to get all the registers right. First thing to do is
  1579. ; restore the banked registers - this needs the same precautions about
  1580. ; user modes as the corresponding entry code.
  1581.                 ADD     R7, R13, #8*4   ; Place to find reg values
  1582.                 ANDS    R1, R5, #Mode_MainMask
  1583.                 ASSERT  (Mode_User:AND:Mode_MainMask) = 0
  1584.                 LDMEQIA R7, {R8-R14}^
  1585.                 BEQ     RegsRestored_Init
  1586.                 MRS     R2, CPSR
  1587.                 BIC     R3, R2, #Mode_MainMask
  1588.                 ORR     R1, R3, R1
  1589.                 MSR     CPSR$all_fields, R1
  1590.                 LDMIA   R7, {R8-R14}
  1591.                 MSR     CPSR$all_fields, R2
  1592. RegsRestored_Init
  1593. ; PC value wanted is the address of the aborting instruction plus 4
  1594. ; (we don't want to retry it), CPSR value wanted is the entry SPSR
  1595. ; value.
  1596.                 ADD     R4, R4, #4
  1597.                 STR     R4, [R13, #14*4]
  1598.                 MSR     SPSR$all_fields, R5
  1599. ; Now we're ready to restore the rest of the registers and return.
  1600.                 LDMIA   R13, {R0-R7}
  1601.                 ADD     R13, R13, #14*4
  1602.                 LDMIA   R13!, {PC}^
  1603. ; The initialisation routine
  1604. ; ==========================
  1605. ;
  1606. ; This is as outlined above.
  1607. $AbortModelInit
  1608.                 EXPORT  $AbortModelInit[LEAF]
  1609. ; Initialise the abort model variable, and set the NE condition in the
  1610. ; process.
  1611.                 IMPORT  $AbortModelVar
  1612.                 LDR     R3, =$AbortModelVar
  1613.                 MOVS    R2, #DABORT_MODEL_INITIALISATION
  1614.                 STR     R2, [R3]
  1615. ; Try an aborting LDR.
  1616.                 MOV     R1, R0
  1617.                 LDR     R2, [R1], #4
  1618. ; Try an aborting LDM.
  1619.                 MOV     R1, R0
  1620.                 LDMIA   R1!, {R2}
  1621. ; Get the abort model variable and check whether it is valid. Note we
  1622. ; still have the NE condition at this point.
  1623.                 LDR     R2, [R3]
  1624.         [ BaseRestored
  1625.                 CMPNE   R2, #DABORT_MODEL_BASERESTORED
  1626.         ]
  1627.         [ EarlyAbort
  1628.                 CMPNE   R2, #DABORT_MODEL_EARLYABORT
  1629.         ]
  1630.         [ BaseUpdated
  1631.                 CMPNE   R2, #DABORT_MODEL_BASEUPDATED
  1632.         ]
  1633. ; Set the return value and return.
  1634.                 MOVEQ   R0, #0
  1635.                 MOVNE   R0, #1
  1636.                 MOV     PC, LR
  1637.         ]
  1638. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1639. ;
  1640. ; The end
  1641. ; =======
  1642. ;
  1643.                 END
  1644. ; EOF dabort.s