blob: 9553064d21b0912e039dfd9fe50c4515a3f4f447 [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
#
# Copyright 2021 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
decode ARM Exception Syndrome Register (ESR) values
"""
# TODO(maniscalco): Add a flag that assumes RAS is implemented and
# then further decode the RAS-specific details.
import argparse
import io
import os
import subprocess
import sys
# Return the Stage S1PTW description for the given value.
def s1ptw_desc(value):
return {
0b0: "Fault not on a stage 2 translation for a stage 1 translation table walk",
0b1: "Fault on the stage 2 translation of an access for a stage 1 translation table walk",
}.get(value, "Unexpected S1PTW")
# Return the IFSC description for the given value.
def ifsc_desc(value):
return {
0b000000: "Address size fault, level 0 of translation or translation table base register",
0b000001: "Address size fault, level 1",
0b000010: "Address size fault, level 2",
0b000011: "Address size fault, level 3",
0b000100: "Translation fault, level 0",
0b000101: "Translation fault, level 1",
0b000110: "Translation fault, level 2",
0b000111: "Translation fault, level 3",
0b001001: "Access flag fault, level 1",
0b001010: "Access flag fault, level 2",
0b001011: "Access flag fault, level 3",
0b001101: "Permission fault, level 1",
0b001110: "Permission fault, level 2",
0b001111: "Permission fault, level 3",
0b010000: "Synchronous External abort, not on translation table walk",
0b011000: "Synchronous parity or ECC error on memory access, not on translation table walk",
0b010100: "Synchronous External abort, on translation table walk, level 0",
0b010101: "Synchronous External abort, on translation table walk, level 1",
0b010110: "Synchronous External abort, on translation table walk, level 2",
0b010111: "Synchronous External abort, on translation table walk, level 3",
0b011000: "Synchronous parity or ECC error on memory access, not on translation table walk",
0b011100: "Synchronous parity or ECC error on memory access on translation table walk, level 0",
0b011101: "Synchronous parity or ECC error on memory access on translation table walk, level 1",
0b011110: "Synchronous parity or ECC error on memory access on translation table walk, level 2",
0b011111: "Synchronous parity or ECC error on memory access on translation table walk, level 3",
0b110000: "TLB conflict abort",
0b110001: (
"Unsupported atomic hardware update fault, if the implementation includes "
"ARMv8.1-TTHM. Otherwise reserved."
),
}.get(value, "Unexpected IFSC")
# Return the IFSC, S1PTW, EA, FnV, and SET for the given Instruction Abort ISS.
def unpack_instruction_abort_iss(iss):
ifsc = iss & ((1 << 6) - 1)
iss >>= 6 # eat IFSC
iss >>= 1 # eat RES0
s1ptw = iss & ((1 << 1) - 1)
iss >>= 1 # eat S1PTW
iss >>= 1 # eat RES0
ea = iss & ((1 << 1) - 1)
iss >>= 1 # eat EA
fnv = iss & ((1 << 1) - 1)
iss >>= 1 # eat FnV
set_value = iss & ((1 << 2) - 1)
iss >>= 2 # eat SET
return ifsc, s1ptw, ea, fnv, set_value
# Decode an instruction abort.
def decode_instruction_abort(ec, ec_desc, iss):
ifsc, s1ptw, ea, fnv, set_value = unpack_instruction_abort_iss(iss)
decode_ec(ec_desc)
print(
"ISS --> IFSC=0b{:06b} S1PTW=0b{:01b} EA=0b{:01b} FnV=0b{:01b} SET=0b{:02b}".format(
ifsc, s1ptw, ea, fnv, set_value
)
)
print("IFSC:", ifsc_desc(ifsc))
print("S1PTW:", s1ptw_desc(s1ptw))
if fnv != 0:
print("FnV: FAR is not valid, and holds an UNKNOWN value")
# Return the DFSC description for the given value.
def dfsc_desc(value):
return {
0b000000: "Address size fault, level 0 of translation or translation table base register",
0b000001: "Address size fault, level 1",
0b000010: "Address size fault, level 2",
0b000011: "Address size fault, level 3",
0b000100: "Translation fault, level 0",
0b000101: "Translation fault, level 1",
0b000110: "Translation fault, level 2",
0b000111: "Translation fault, level 3",
0b001001: "Access flag fault, level 1",
0b001010: "Access flag fault, level 2",
0b001011: "Access flag fault, level 3",
0b001101: "Permission fault, level 1",
0b001110: "Permission fault, level 2",
0b001111: "Permission fault, level 3",
0b010000: "Synchronous External abort, not on translation table walk",
0b011000: "Synchronous parity or ECC error on memory access, not on translation table walk",
0b010100: "Synchronous External abort, on translation table walk, level 0",
0b010101: "Synchronous External abort, on translation table walk, level 1",
0b010110: "Synchronous External abort, on translation table walk, level 2",
0b010111: "Synchronous External abort, on translation table walk, level 3",
0b011000: "Synchronous parity or ECC error on memory access, not on translation table walk",
0b011100: "Synchronous parity or ECC error on memory access on translation table walk, level 0",
0b011101: "Synchronous parity or ECC error on memory access on translation table walk, level 1",
0b011110: "Synchronous parity or ECC error on memory access on translation table walk, level 2",
0b011111: "Synchronous parity or ECC error on memory access on translation table walk, level 3",
0b100001: "Alignment fault",
0b110000: "TLB conflict abort",
0b110001: (
"Unsupported atomic hardware update fault, if the implementation "
"includes ARMv8.1-TTHM. Otherwise reserved."
),
0b110100: "IMPLEMENTATION DEFINED fault (Lockdown)",
0b110101: "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access)",
0b111101: "Section Domain Fault, used only for faults reported in the PAR_EL1",
0b111110: "Page Domain Fault, used only for faults reported in the PAR_EL1",
}.get(value, "Unexpected DFSC")
# Return the WnR description for the given value.
def wnr_desc(value):
return {
0b0: "Abort caused by an instruction reading from a memory location",
0b1: "Abort caused by an instruction writing to a memory location",
}.get(value, "Unexpected WnR")
# Return the CM description for the given value.
def cm_desc(value):
return {
0b0: "The Data Abort was not generated by the execution of a cache maintenance instruction",
0b1: (
"The Data Abort was generated by the execution of a cache maintenance "
" instruction or by a synchronous fault on the execution of an address "
"translation instruction (DC ZVA does not count as a cache maintenance "
"instruction"
),
}.get(value, "Unexpected CM")
# Return the SAS description for the given value.
def sas_desc(value):
return {
0b00: "Byte",
0b01: "Halfword",
0b10: "Word",
0b11: "Doubleword",
}.get(value, "Unexpected SAS")
# Return the DFSC, WnR, S1PTW, CM, EA, FnV, SET, VNCR, AR, SF, SRT, SSE,
# SAS, and ISV for the given Data Abort ISS.
def unpack_data_abort_iss(iss):
dfsc = iss & ((1 << 6) - 1)
iss >>= 6 # eat DFSC
wnr = iss & ((1 << 1) - 1)
iss >>= 1 # eat WNR
s1ptw = iss & ((1 << 1) - 1)
iss >>= 1 # eat S1PTW
cm = iss & ((1 << 1) - 1)
iss >>= 1 # eat CM
ea = iss & ((1 << 1) - 1)
iss >>= 1 # eat EA
fnv = iss & ((1 << 1) - 1)
iss >>= 1 # eat FnV
set_value = iss & ((1 << 2) - 1)
iss >>= 2 # eat SET
vncr = iss & ((1 << 1) - 1)
iss >>= 1 # eat VNCR
ar = iss & ((1 << 1) - 1)
iss >>= 1 # eat AR
sf = iss & ((1 << 1) - 1)
iss >>= 1 # eat SF
srt = iss & ((5 << 1) - 1)
iss >>= 5 # eat SRT
sse = iss & ((1 << 1) - 1)
iss >>= 1 # eat SSE
sas = iss & ((1 << 2) - 1)
iss >>= 2 # eat SAS
isv = iss & ((1 << 1) - 1)
iss >>= 1 # eat ISV
return (
dfsc,
wnr,
s1ptw,
cm,
ea,
fnv,
set_value,
vncr,
ar,
sf,
srt,
sse,
sas,
isv,
)
# Decode a data abort.
def decode_data_abort(ec, ec_desc, iss):
(
dfsc,
wnr,
s1ptw,
cm,
ea,
fnv,
set_value,
vncr,
ar,
sf,
srt,
sse,
sas,
isv,
) = unpack_data_abort_iss(iss)
decode_ec(ec_desc)
print(
"ISS --> DFSC=0b{:06b} WnR=0b{:01b} S1PTW=0b{:01b} CM=0b{:01b} EA=0b{:01b} FnV=0b{:01b} SET=0b{:02b} VNCR=0b{:01b} AR=0b{:01b} SF=0b{:01b} SRT=0b{:05b} SSE=0b{:01b} ISV=0b{:01b}".format(
dfsc,
wnr,
s1ptw,
cm,
ea,
fnv,
set_value,
vncr,
ar,
sf,
srt,
sse,
isv,
)
)
print("DFSC:", dfsc_desc(dfsc))
if ea != 1 and dfsc != 0b110101 and dfsc != 0b110001:
print("WnR:", wnr_desc(wnr))
print("S1PTW:", s1ptw_desc(s1ptw))
print("CM:", cm_desc(cm))
if dfsc == 0b100000 and fnv == 1:
print("FnV: FAR is not valid, and holds an UNKNOWN value")
if isv == 1:
print("SAS: Access size is", sas_desc(sas))
# Decode just the EC.
def decode_ec(ec_desc):
print("EC:", ec_desc)
# Decode the EC and ISS.
def decode_ec_iss(ec, iss):
if ec == 0b000000:
decode_ec("Unknown reason")
elif ec == 0b000001:
decode_ec("Trapped WFI or WFE instruction execution")
elif ec == 0b000011:
decode_ec(
"Trapped MCR or MRC access with (coproc==1111) that is not reported using EC 0b000000"
)
elif ec == 0b000100:
decode_ec(
"Trapped MCRR or MRRC access with (coproc==1111) that is not reported using EC 0b000000"
)
elif ec == 0b000101:
decode_ec("Trapped MCR or MRC access with (coproc==1110)")
elif ec == 0b000110:
decode_ec("Trapped LDC or STC access")
elif ec == 0b000111:
decode_ec(
"Trapped access to SVE, Advanced SIMD, or floating-point functionality"
)
elif ec == 0b001000:
decode_ec(
"Trapped VMRS access, from ID group trap, that is not reported using EC 0b000111"
)
elif ec == 0b001001:
decode_ec(
"Trapped Pointer Authentication instruction because HCR_EL2.API==0 or SCR_EL3.API==0"
)
elif ec == 0b001010:
decode_ec(
"Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction"
)
elif ec == 0b001100:
decode_ec("Trapped MRRC access with (coproc==1110)")
elif ec == 0b001110:
decode_ec("Illegal Execution state")
elif ec == 0b010001:
decode_ec("SVC instruction execution in AArch32 state")
elif ec == 0b010010:
decode_ec(
"HVC instruction execution in AArch32 state, when HVC is not disabled"
)
elif ec == 0b010011:
decode_ec(
"SMC instruction execution in AArch32 state, when SMC is not disabled"
)
elif ec == 0b010101:
decode_ec("SVC instruction execution in AArch64 state")
elif ec == 0b010110:
decode_ec(
"HVC instruction execution in AArch64 state, when HVC is not disabled"
)
elif ec == 0b010111:
decode_ec(
"SMC instruction execution in AArch64 state, when SMC is not disabled"
)
elif ec == 0b011000:
decode_ec(
"Trapped MSR, MRS or System instruction execution in AArch64 state"
)
elif ec == 0b011001:
decode_ec("Trapped SVE functionality")
elif ec == 0b011010:
decode_ec("Trapped ERET, ERETAA, or ERETAB instruction execution")
elif ec == 0b011100:
decode_ec(
"Exception from a Pointer Authentication instruction authentication failure"
)
elif ec == 0b011111:
decode_ec("IMPLEMENTATION DEFINED exception to EL3")
elif ec == 0b100000:
ec_desc = "Instruction Abort from a lower Exception level, that might be using AArch32 or AArch64"
decode_instruction_abort(ec, ec_desc, iss)
elif ec == 0b100001:
ec_desc = "Instruction Abort taken without a change in Exception level"
decode_instruction_abort(ec, ec_desc, iss)
elif ec == 0b100010:
decode_ec("PC alignment fault exception")
elif ec == 0b100100:
ec_desc = "Data Abort from a lower Exception level, that might be using AArch32 or AArch64"
decode_data_abort(ec, ec_desc, iss)
elif ec == 0b100101:
ec_desc = "Data Abort taken without a change in Exception level"
decode_data_abort(ec, ec_desc, iss)
elif ec == 0b100110:
decode_ec("SP alignment fault exception")
elif ec == 0b101000:
decode_ec("Trapped floating-point exception taken from AArch32 state")
elif ec == 0b101100:
decode_ec("Trapped floating-point exception taken from AArch64 state")
elif ec == 0b101111:
decode_ec("SError interrupt")
elif ec == 0b110000:
decode_ec(
"Breakpoint exception from a lower Exception level, that might be using AArch32 or AArch64"
)
elif ec == 0b110001:
decode_ec(
"Breakpoint exception taken without a change in Exception level"
)
elif ec == 0b110010:
decode_ec(
"Software Step exception from a lower Exception level, that might be using AArch32 or AArch64"
)
elif ec == 0b110011:
decode_ec(
"Software Step exception taken without a change in Exception level"
)
elif ec == 0b110100:
decode_ec(
"Watchpoint exception from a lower Exception level, that might be using AArch32 or AArch64"
)
elif ec == 0b110101:
decode_ec(
"Watchpoint exception taken without a change in Exception level"
)
elif ec == 0b111000:
decode_ec("BKPT instruction execution in AArch32 state")
elif ec == 0b111010:
decode_ec("Vector Catch exception from AArch32 state")
elif ec == 0b111100:
decode_ec("BRK instruction execution in AArch64 state")
else:
decode_ec("Unexpected EC value")
def decode_esr(esr):
# Extract ISS from bits [24:0].
iss_mask = (1 << 25) - 1
iss = esr & iss_mask
# Extract IL from bit [25].
il = (esr >> 25) & 1
# Extract EC from bits [31:26].
ec = esr >> 26
print(
"ESR=0x{:08x} --> EC=0b{:06b} IL=0b{:01b} ISS=0x{:07x}".format(
esr, ec, il, iss
)
)
decode_ec_iss(ec, iss)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("esr", help="32-bit ESR value")
args = parser.parse_args()
esr = int(args.esr, 16)
if esr > (2**32) - 1:
print(
"ERROR: ESR value too large to be a 32-bit value: 0x{0:02x}".format(
esr
)
)
sys.exit(1)
decode_esr(esr)
if __name__ == "__main__":
main()