From f1c7aac7c5504e99b916371c8f7861047df9fe5a Mon Sep 17 00:00:00 2001 From: Pawan Rai Date: Tue, 1 Sep 2026 12:10:44 +0530 Subject: [PATCH 1/4] plat-qcom: wildcat: nord: enable diagnostic ring buffer Add the platform configuration required by the diagnostic ring buffer on the Wildcat architecture, including the buffer layout shared by all Wildcat targets and the IMEM base and size for Nord. Default CFG_QCOM_DIAG_LOG to CFG_TEE_CORE_DEBUG so that the buffer is enabled on debug builds. Change-Id: I440a6aeb25624e6c87877faad774478fb491dca2 Signed-off-by: Pawan Rai --- core/arch/arm/plat-qcom/wildcat/arch_config.h | 5 +++++ core/arch/arm/plat-qcom/wildcat/nord/target.mk | 2 ++ core/arch/arm/plat-qcom/wildcat/nord/target_config.h | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/core/arch/arm/plat-qcom/wildcat/arch_config.h b/core/arch/arm/plat-qcom/wildcat/arch_config.h index 490346af0..6874ea929 100644 --- a/core/arch/arm/plat-qcom/wildcat/arch_config.h +++ b/core/arch/arm/plat-qcom/wildcat/arch_config.h @@ -6,4 +6,9 @@ #ifndef ARCH_CONFIG_H #define ARCH_CONFIG_H +#define IMEM_DIAG_OFFSET UL(0x720) +#define DIAG_SIZE UL(0x3000) +#define DIAG_BASE (IMEM_BASE + IMEM_SIZE - DIAG_SIZE) +#define DIAG_LOG_START_INFO (IMEM_BASE + IMEM_DIAG_OFFSET) + #endif /* ARCH_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/wildcat/nord/target.mk b/core/arch/arm/plat-qcom/wildcat/nord/target.mk index c774f510f..dd66a4173 100644 --- a/core/arch/arm/plat-qcom/wildcat/nord/target.mk +++ b/core/arch/arm/plat-qcom/wildcat/nord/target.mk @@ -11,3 +11,5 @@ $(call force,CFG_TEE_CORE_NB_CORE,18) CFG_TZDRAM_START ?= 0xBC280000 CFG_TEE_RAM_VA_SIZE ?= 0x00200000 CFG_TA_RAM_VA_SIZE ?= 0x07B80000 + +CFG_QCOM_DIAG_LOG ?= $(CFG_TEE_CORE_DEBUG) diff --git a/core/arch/arm/plat-qcom/wildcat/nord/target_config.h b/core/arch/arm/plat-qcom/wildcat/nord/target_config.h index 3d7065ff7..f3bdbc373 100644 --- a/core/arch/arm/plat-qcom/wildcat/nord/target_config.h +++ b/core/arch/arm/plat-qcom/wildcat/nord/target_config.h @@ -18,4 +18,9 @@ #define DRAM2_BASE ULL(0x8800000000) #define DRAM2_SIZE ULL(0x3800000000) +/* IMEM and Diagnostic buffer */ +#define TCSR_BOOT_MISC_DETECT UL(0x1FD3000) +#define IMEM_BASE UL(0x14680000) +#define IMEM_SIZE UL(0x19000) + #endif /* TARGET_CONFIG_H */ From 744e7a87ffaded8bfcc68a61c63992884d6ad4d1 Mon Sep 17 00:00:00 2001 From: Pawan Rai Date: Tue, 1 Sep 2026 12:11:03 +0530 Subject: [PATCH 2/4] plat-qcom: wildcat: cacao: enable diagnostic ring buffer Cacao already carries IMEM_BASE and IMEM_SIZE in its target_config.h, and the Wildcat arch_config.h now defines the shared buffer layout (IMEM_DIAG_OFFSET, DIAG_SIZE, DIAG_BASE, DIAG_LOG_START_INFO). Default CFG_QCOM_DIAG_LOG to CFG_TEE_CORE_DEBUG so that the buffer is enabled on debug builds. Change-Id: Ia472203bda34c738e36e06b65326d42a83ee421d Signed-off-by: Pawan Rai --- core/arch/arm/plat-qcom/wildcat/cacao/target.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/arch/arm/plat-qcom/wildcat/cacao/target.mk b/core/arch/arm/plat-qcom/wildcat/cacao/target.mk index 510871be3..be667eb04 100644 --- a/core/arch/arm/plat-qcom/wildcat/cacao/target.mk +++ b/core/arch/arm/plat-qcom/wildcat/cacao/target.mk @@ -11,3 +11,5 @@ $(call force,CFG_TEE_CORE_NB_CORE,8) CFG_TZDRAM_START ?= 0x80fcd000 CFG_TEE_RAM_VA_SIZE ?= 0x147000 CFG_TA_RAM_VA_SIZE ?= 0x300000 + +CFG_QCOM_DIAG_LOG ?= $(CFG_TEE_CORE_DEBUG) From 11c762c896374d96a898fc0e5b097874e29c5774 Mon Sep 17 00:00:00 2001 From: Pawan Rai Date: Tue, 1 Sep 2026 12:11:39 +0530 Subject: [PATCH 3/4] plat-qcom: bruin: shikra: enable diagnostic ring buffer Shikra already carries IMEM_BASE and IMEM_SIZE in its target_config.h. Add the shared buffer layout macros (IMEM_DIAG_OFFSET, DIAG_SIZE, DIAG_BASE, DIAG_LOG_START_INFO) to the Bruin arch_config.h, and default CFG_QCOM_DIAG_LOG to CFG_TEE_CORE_DEBUG so the buffer is enabled on debug builds. Change-Id: Ie924e5f56d80a4103be60c5061fbfeadb69b5635 Signed-off-by: Pawan Rai --- core/arch/arm/plat-qcom/bruin/arch_config.h | 5 +++++ core/arch/arm/plat-qcom/bruin/shikra/target.mk | 2 ++ core/arch/arm/plat-qcom/bruin/shikra/target_config.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/core/arch/arm/plat-qcom/bruin/arch_config.h b/core/arch/arm/plat-qcom/bruin/arch_config.h index 79212dcd9..1d5e92dcb 100644 --- a/core/arch/arm/plat-qcom/bruin/arch_config.h +++ b/core/arch/arm/plat-qcom/bruin/arch_config.h @@ -9,4 +9,9 @@ #define GICD_BASE UL(0x0f200000) #define GICR_BASE UL(0x0f260000) +#define IMEM_DIAG_OFFSET UL(0x720) +#define DIAG_SIZE UL(0x3000) +#define DIAG_BASE (IMEM_BASE + IMEM_SIZE - DIAG_SIZE) +#define DIAG_LOG_START_INFO (IMEM_BASE + IMEM_DIAG_OFFSET) + #endif /* ARCH_CONFIG_H */ diff --git a/core/arch/arm/plat-qcom/bruin/shikra/target.mk b/core/arch/arm/plat-qcom/bruin/shikra/target.mk index 14ae1120a..90f8c47e5 100644 --- a/core/arch/arm/plat-qcom/bruin/shikra/target.mk +++ b/core/arch/arm/plat-qcom/bruin/shikra/target.mk @@ -1 +1,3 @@ # Placeholder for target specific configs. + +CFG_QCOM_DIAG_LOG ?= $(CFG_TEE_CORE_DEBUG) diff --git a/core/arch/arm/plat-qcom/bruin/shikra/target_config.h b/core/arch/arm/plat-qcom/bruin/shikra/target_config.h index e2a4aeb39..77bd861c9 100644 --- a/core/arch/arm/plat-qcom/bruin/shikra/target_config.h +++ b/core/arch/arm/plat-qcom/bruin/shikra/target_config.h @@ -14,4 +14,6 @@ #define IMEM_BASE UL(0x0c100000) #define IMEM_SIZE UL(0x00020000) +#define TCSR_BOOT_MISC_DETECT UL(0x3D3000) + #endif /* TARGET_CONFIG_H */ From dd8a3c97d8a5297e150fbb6dad94093d6fcf6b21 Mon Sep 17 00:00:00 2001 From: Pawan Rai Date: Tue, 15 Sep 2026 22:07:52 +0530 Subject: [PATCH 4/4] scripts: add diag_log_parser.py for Qualcomm OP-TEE DIAG log Parse the OP-TEE diagnostic ring buffer written into IMEM by diag_log.c. Handles full RAM dumps (OCIMEM.BIN) with either a known DIAG_BASE offset (--offset) or automatic magic-scan mode (--scan), as well as pre-extracted DIAG region slices. Change-Id: I49a1145c9983d32b2c3ac8b50a6ec4916de606e0 Signed-off-by: Pawan Rai --- scripts/diag_log_parser.py | 223 +++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 scripts/diag_log_parser.py diff --git a/scripts/diag_log_parser.py b/scripts/diag_log_parser.py new file mode 100755 index 000000000..8763741c5 --- /dev/null +++ b/scripts/diag_log_parser.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# +# Parse a Qualcomm OP-TEE DIAG log buffer extracted from a RAM/crash dump. +# +# The DIAG region lives in IMEM at: +# DIAG_BASE = IMEM_BASE + IMEM_SIZE - DIAG_SIZE (0x3000 bytes) +# +# Binary layout (matches diag_log.c): +# struct diag_hdr { uint32 version; uint32 magic; } +# struct diag_conf { uint32 buf_offset; uint32 buf_size; } +# struct circ_wo_buf{ uint32 wrap; uint32 head; uint8 buf[]; } +# +# Usage: +# # Auto-scan OCIMEM ramdump (no offset required): +# python3 diag_log_parser.py --input OCIMEM.BIN --scan +# +# # OCIMEM ramdump with known DIAG_BASE offset: +# python3 diag_log_parser.py --input OCIMEM.BIN --offset 0x +# +# # From a pre-extracted DIAG region (already sliced out of OCIMEM): +# python3 diag_log_parser.py --input diag_region.bin +# +# # Pipe into symbolize.py for address resolution: +# python3 diag_log_parser.py --input OCIMEM.BIN --scan | \ +# python3 symbolize.py -d + +import argparse +import os +import struct +import sys + +DIAG_MAGIC_INIT = 0x47414944 # "DIAG" little-endian — log valid +DIAG_MAGIC_FAILED = 0xDEADBEEF # init failed +DIAG_MAGIC_DLOAD = 0xD15AB1ED # dload mode, log not written + +MAGIC_NAMES = { + DIAG_MAGIC_INIT: 'DIAG_MAGIC_INIT (valid)', + DIAG_MAGIC_FAILED: 'DIAG_MAGIC_FAILED (init failed — buffer invalid)', + DIAG_MAGIC_DLOAD: 'DIAG_MAGIC_DLOAD (dload mode — no log written)', +} + +# struct offsets +OFF_VERSION = 0 # uint32 +OFF_MAGIC = 4 # uint32 +OFF_BUF_OFFSET = 8 # uint32 +OFF_BUF_SIZE = 12 # uint32 +OFF_WRAP = 16 # uint32 +OFF_HEAD = 20 # uint32 +OFF_BUF_START = 24 # uint8[] starts here (matches offsetof circ_wo_buf.buf) + + +SCAN_STEP = 0x1000 # DIAG_BASE is always page-aligned + + +def parse_args(): + p = argparse.ArgumentParser( + description='Parse a Qualcomm OP-TEE DIAG log buffer from a crash dump', + epilog=''' +Examples: + # Auto-scan OCIMEM ramdump for the DIAG magic (no need to know DIAG_BASE): + python3 diag_log_parser.py --input OCIMEM.BIN --scan + + # OCIMEM ramdump with known DIAG_BASE offset: + # (for cacao: IMEM_BASE=0x14680000, IMEM_SIZE=0x19000, DIAG_SIZE=0x3000 + # => DIAG_BASE = 0x14680000 + 0x19000 - 0x3000 = 0x14696000) + python3 diag_log_parser.py --input OCIMEM.BIN --offset 0x14696000 + + # Bobcat uses DIAG_SIZE=0x6000 and a fixed DIAG_BASE=0x8608000: + python3 diag_log_parser.py --input OCIMEM.BIN --offset 0x8608000 --size 0x6000 + + # Pre-extracted DIAG region (already sliced out of OCIMEM): + python3 diag_log_parser.py --input diag_region.bin + + # Pipe through symbolize.py: + python3 diag_log_parser.py --input OCIMEM.BIN --scan | \\ + python3 symbolize.py -d out/cacao/ +''', + formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument('--input', '-i', required=True, + help='Binary file: pre-extracted DIAG region or full RAM dump') + p.add_argument('--offset', '-o', default='0', + help='Byte offset of DIAG_BASE within the input file ' + '(hex or decimal, default: 0)') + p.add_argument('--size', '-s', default='0x3000', + help='DIAG region size in bytes (default: 0x3000)') + p.add_argument('--scan', action='store_true', + help='Scan the input file for the DIAG magic instead of using --offset') + p.add_argument('--verbose', '-v', action='store_true', + help='Print header fields before the log text') + return p.parse_args() + + +def read_u32(data, offset): + return struct.unpack_from(' len(data): + print(f'ERROR: buf_offset(0x{buf_offset:x}) + buf_size(0x{buf_size:x}) ' + f'exceeds region size(0x{len(data):x})', file=sys.stderr) + sys.exit(1) + + if head >= buf_size: + print(f'ERROR: head(0x{head:x}) > buf_size(0x{buf_size:x}) — dump corrupt', + file=sys.stderr) + sys.exit(1) + + buf = data[buf_offset: buf_offset + buf_size] + + # Reconstruct log order from circular buffer: + # wrap == 0: buffer has not wrapped, valid data is buf[0..head] + # wrap > 0: buffer has wrapped, oldest data starts at head + if wrap == 0: + log_bytes = buf[:head] + else: + # oldest data: from head to end, then 0 to head + log_bytes = buf[head:] + buf[:head] + + log_text = log_bytes.decode('utf-8', errors='replace') + + if args.verbose: + total = head if wrap == 0 else buf_size + print(f'--- log ({total} bytes, wrap={wrap}) ---', file=sys.stderr) + + sys.stdout.write(log_text) + if log_text and not log_text.endswith('\n'): + sys.stdout.write('\n') + + +if __name__ == '__main__': + main()