📄 dabort.txt
字号:
before a data abort can arise. The means by which this is done is
described under "Assembly-time Options for Multiple Abort Models" below.
* Options to say how the OS-specific handler will be called:
-PD 'HandlerName SETS "<handler_name>"'
(Mandatory.) The name of the OS-specific handler. Its exact
interpretation depends on the calling standard used - see the next
entry.
-PD 'HandlerCallStd SETS "<calling_standard_name>"'
(Defaults to "APCS_NOSWST".) Define the procedure calling standard to be
used when calling the OS-specific handler. Possible values are:
APCS_NOSWST: The "no software stack checking" variant of the ARM
Procedure Calling Standard. A symbol defined by the "HandlerName"
option will be IMPORTed and a procedure call generated to it to
implement the OS-specific handler call. Details of the parameters to
and return value from this call appear below.
APCS_SWST: The "software stack checking" variant of the ARM Procedure
Calling Standard. This is identical to the APCS_NOSWST option, except
that before the call, the "sl" register (R10) will be loaded with an
OS-supplied value.
APCS_MACRO: Arguments will be marshalled and registers preserved (if
necessary) as though for the APCS_NOSWST choice, but a macro will be
expanded in place of generating a BL to an external procedure. The
macro's name is given by the "HandlerName" option, and takes no
parameters. Entry and exit conditions for the macro are as specified
by the "no software stack checking" variant of the ARM Procedure
Calling Standard, except that R14 does not contain a return link, and
it should "return" by executing past the end of the macro. (This
essentially allows a very simple OS-specific handler to be implemented
in-line.)
-PD 'HandlerCallMode SETS "<mode_name>"'
(Defaults to "Supervisor" for APCS_NOSWST and APCS_SWST calling
standards, "Abort" for APCS_MACRO calling standard.) Define the mode in
which the OS-specific handler is to be invoked. Possible values are
"Abort" (to remain in Abort-32 mode), "Supervisor" (to transfer to
Supervisor-32 mode) and "System" (to transfer to System-32 mode).
-PD 'HandlerSL SETS "<symbol>"'
(Mandatory for APCS_SWST calling standard, unnecessary and unused
otherwise.) For the APCS_SWST calling standard, a suitable stack limit
value must be loaded for the procedure call to the OS-specific handler.
This is done by IMPORTing the given symbol, which should be the address
of a word containing the stack limit value.
* Options to say what parameters will be passed to the OS-specific handler:
-PD 'PassSPSR SETL {TRUE}'
Pass the SPSR_abort value, which was copied from the CPSR when the
ARM took the data abort trap. This would most likely be used to
determine whether the processor was in a privileged or user mode (by
testing whether bits 3:0 != 0000 or == 0000 respectively), but also
allows tests such as whether the processor was in Thumb state, whether
interrupts were enabled, etc.
-PD 'PassInstrAddr SETL {TRUE}'
Pass the address of the aborting instruction. The instruction itself can
be obtained (if desired) by dereferencing this address, taking the CPSR
T bit (bit 5) value into account. (This means that the "PassSPSR" option
above must also be specified if the OS-specific handler wants to access
the instruction on a Thumb-aware system.)
-PD 'PassRegDumpAddr SETL {TRUE}'
Pass the address of a 15-word dump of the values of registers R0-R14
made on entry to the data abort veneer, and possibly adjusted to unwind
some or all of the effects of the aborting instruction. Note however
that not all of the effects of the aborting instruction are guaranteed
to have been unwound - some can't be in the cases of LDMs, of errors,
and (if supported) of pre-indexed LDRs with base register = offset
register. Similarly, the OS-specific handler should not write modified
values to this dump; if it does, there can be no guarantee that it will
get the "expected" results.
Some further details:
* For banked registers, the values in this 15-word register dump are
those for the processor mode in which the aborting instruction was
executed.
* As far as memory protection goes, this register dump will be on the
abort stack and so will be accessible by code which can access the
abort stack.
-PD 'PassXferAddr SETL {TRUE}'
Pass the address of the data that was to have been loaded or stored. In
the case of a multi-word load or store (ARM LDC/LDM/STC/STM, or Thumb
LDM/POP/PUSH/STM), this will be the starting address of the transfer,
and the actual aborting address may occur at a later point in the
transfer. (Using ARM processor core facilities only, it is impossible
to determine the exact aborting address in this case without performing
"trial accesses" to the memory system: this could result in unwanted
behaviour for some systems, so should be left up to the OS-specific
handler.)
Note that it may be possible to use system facilities such as the
standard coprocessor 15 Fault Address Register to determine the aborting
address more easily than processor-core-only code can. If such
facilities exist in a given system, it will probably be better for the
OS-specific handler to use them and not to request the "PassXferAddress"
option.
See "Parameters of the OS-specific Handler Call" below for more details of
the call to the OS-specific handler.
* Options to specify what return values the OS-specific handler may produce:
-PD 'ReturnNormal SETL {TRUE}'
Allow the OS-specific handler to return 0x0 to request that the original
program should be returned to.
-PD 'ReturnUndef SETS "<value_or_symbol>"'
(Defaults to not allowing this return value.) Allow the OS-specific
handler to return 0x4 to request that a trap to the undefined
instruction vector should be faked. "<value_or_symbol>" specifies the
actual address to be branched to, as either a hexadecimal number (e.g.
"0x00000004" or "0xFFFF0004") or an IMPORTed symbol.
-PD 'ReturnToNext SETS "<symbol>"'
(Defaults to not allowing this return value.) Allow the OS-specific
handler to return 0x10 to request that another data abort handler should
be invoked. The given symbol will be IMPORTed and treated as the address
of this second data abort handler.
-PD 'ReturnAddress SETL {TRUE}'
Allow the OS-specific handler to return an address to which control will
be transferred after unwinding the data abort veneer's stack and doing
any other "cleaning up" that is necessary.
At least one of the options that may be used when an error occurs must be
specified - see "Return Value from the OS-specific Handler Call" below for
more details of this, and for other information about the return value.
* An option to remove support for Thumb:
-PD 'SuptThumb SETL {FALSE}'
If specified, this will cause the code that handles Thumb instructions not
to be assembled. This reduces the code size of the data abort veneer when
it is only to be run on non-Thumb-aware processor cores.
* An option to control error detection:
-PD 'StrictErrors SETL {FALSE}'
If "StrictErrors" is left at (or set to) its default value of {TRUE}, the
data abort veneer will generate an error for any instruction which is
architecturally undefined in the areas relevant to data abort unwinding
(address generation and base register writeback in particular), and will
do so consistently across all abort models. This will happen regardless of
whether this is particularly relevant to the correct functioning of the
data abort veneer's code.
If "StrictErrors" is set to {FALSE}, the data abort veneer will only
generate an error for conditions that it needs to detect in order to
function correctly. This saves code, at the expense of incompatibility
between different abort models with respect to precisely which errors are
detected.
Note: Not all architecturally undefined instructions are detected as
errors even with "StrictErrors" equal to {TRUE}. E.g. use of the
SPSR->CPSR transferring version of LDM (i.e. LDM Rn,{<registers>,PC}^)
in user or system modes is UNPREDICTABLE, but the reason for this is the
non-existence of a user/system mode SPSR, which is not an area relevant
to data abort unwinding. Similarly, architectural undefinedness in the
area of precisely what value gets loaded or stored will generally not be
detected - e.g. a SWP with Rn = R15 will be detected, but one with Rd =
R15 or Rm = R15 will not be. See "Errors" below for a list of the errors
that are detected.
Assembly-time Options for Multiple Abort Models
-----------------------------------------------
The following assembly-time options are used when the code is assembled to
handle more than one of the possible abort models, to specify how it is
determined at run time which abort model to use.
* An option to specify a variable that identifies the abort model to use:
-PD 'AbortModelVar SETS "<name>"'
This option is mandatory if the code is assembled for more than one abort
model, and ignored if the code is assembled for just one abort model (or
is used during initialisation only if the "AbortModelInit" option is also
specified - see below).
The code will IMPORT a symbol called "<name>" and treat it as the address
of a data word. The value of the word is read by the data abort veneer and
used to identify the abort model. Provisionally, the following values are
allocated to the various abort models:
0: Base Restored Abort Model
1: Legacy "early aborts" model
3: Base Updated Abort Model
The authoritative sources for these abort model identifiers is however the
C header file.
* An option to specify the name of an initialisation routine which
determines the abort model in use:
-PD 'AbortModelInit SETS "<name>"'
If unspecified or set to the empty string, the initialisation routine will
not be assembled. If set to a non-empty string, the initialisation routine
will be assembled, its entry point will be labelled "<name>" and the
resulting label will be EXPORTed.
To use the initialisation routine:
- Install the data abort handler.
- Call the initialisation routine in a mode other than abort mode, before
any code that can cause a data abort exception is executed, and not
allowing it to be interrupted by any code that can cause a data abort.
The routine takes a single parameter, which should be the address of a
word of memory which is guaranteed to abort.
- The initialisation routine returns zero to indicate that initialisation
was successful, in which case the variable specified by "AbortModelVar"
will now contain the correct value for the processor's abort model.
- The initialisation routine returns a non-zero value to indicate that
initialisation failed. The only plausible reasons for initialisation
failure with the anticipated implementation are that the supplied
address did not in fact cause an abort as expected, or that the
processor did not conform to any of the selected abort models. Note that
this second reason for an error means that the initialisation routine
can be useful even when only one abort model is being assembled, as it
allows the code to detect that it is being run on an unsuitable
processor.
The initialisation routine works by issuing some aborting loads from the
specified address, then looking at the base register contents in special
case code within the data abort veneer to see how the processor behaved.
It thus does not need to access any sort of processor ID code, but does
require the data abort veneer to be installed before it is called.
Possible Extra Assembly-time Options
------------------------------------
The following assembly-time options are possible extra ones that may be needed
at some point, but are not included in this version:
* Options to support re-enabling interrupts at a suitable point. At present,
this code assumes that the OS-specific handler is in charge of re-enabling
interrupts if necessary.
* An option to specify that load instructions which load their own base
register *and* specify base register writeback are to be supported, on the
basis that base register writeback has or has not occurred (as specified
by the abort model) and that the base register load has been suppressed:
-PD 'SuptLoadBaseWB SETL {TRUE}'
The issue here is that while these instructions are architecturally
UNPREDICTABLE, most ARM implementations to date have implemented them as
first writing back to the base register, then loading its contents. (The
overall effect is the same as if writeback had not been specified.) At
least some (old) code uses these instructions, and it is unknown how
widely they occur: it may be necessary in some systems to support them
despite them being UNPREDICTABLE.
If this option is not specified, such instructions will generate an error.
* An option to say whether LDR/STR instructions with writeback and a
register offset, and the same register specified as both the base register
and the index register are supported as far as possible. Post-indexed ones
cannot be supported in general and are definitely not architecturally
defined; pre-indexed ones can be, but with various levels of difficulty
depending on the abort model and other options.
-PD 'SuptBaseEqIndex SETL {TRUE}'
If not specified, pre-indexed instructions of the type described will not
be supported. The instructions concerned are ones of the forms:
LDR Rd,[Rn,Rn]! STR Rd,[Rn,Rn]!
LDR Rd,[Rn,-Rn]! STR Rd,[Rn,-Rn]!
LDR Rd,[Rn,Rn,<shift>]! STR Rd,[Rn,Rn,<shift>]!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -