# TDA4VH U-Boot 早期异常 — dump 分析报告

> 本报告对应 `error_tiboot3` 复现，基于已打 patch（early_crash_record + efi_gd cookie + one-shot）后的干净首发现场。
> dump 文件：`tmp/error_tiboot3/80000000-0817.img`（0x80000000 起 128MB）
> 寄存器：`tmp/error_tiboot3/reg.txt`
> 构建产物：`tmp/error_tiboot3/build/a72/`（u-boot ELF、System.map、.config）

---

## 1. 结论摘要

1. **patch 全部生效**：`exception_count = 1`（无递归），`efi_gd_state = UNSAVED`（cookie 修复挡住错误 gd 恢复），`x18 = gd = 0x80477EA0`（全程完好）。CPU 最终正常走到 `hang()`。
2. **真正的首次异常**（此前从未被干净捕获）：`fdtdec_parse_phandle_with_args + 0xe0`，发生在 **UART 串口驱动 probe 阶段解析 `clocks` 时钟属性**时。
3. **ESR = 0x02000000（EC=0x00 "Unknown reason"）**，异常落在一条 `b.lo` 条件分支上——**这不是软件 bug，而是硬件级同步异常**（内存子系统/互联/防火墙类）。
4. **推翻旧结论**：之前"首发在 ti_sci_probe → device_bind_driver"是误判，那是递归几千轮后幸存的较晚帧，不是真正的第一次。

---

## 2. 关键符号地址（patched build）

| 符号 | 地址 | 段 |
|---|---|---|
| `_exception_entry` | 0x80802010 | text |
| `do_sync` | 0x80802CC4 | text |
| `early_crash_capture` | 0x80802E8C | text |
| `early_crash_halt` | 0x80802F38 | text |
| `early_crash_record` | 0x80908C38 | .data |
| `efi_gd_state` | 0x8090F874 | .data |
| `efi_gd` | 0x80951B58 | .bss |
| `efi_save_gd` | 0x8088B4C4 | text |
| `efi_restore_gd` | 0x8088B4E4 | text |
| `device_bind_driver_to_node` | 0x8083A5AC | text |
| `ti_sci_probe` | 0x80848A18 | text |
| `fdtdec_parse_phandle_with_args` | 0x808B8360 | text |
| `hang` | 0x808B9FFC | text |
| gd（运行时） | 0x80477EA0 | DDR |

---

## 3. patch 生效验证

`early_crash_record @ 0x80908C38`：

| 字段 | 偏移 | 值 | 结论 |
|---|---|---|---|
| magic | +0x00 | `0x5542435241534831` (UBCRASH1) | 记录有效 |
| version | +0x08 | 1 | |
| state | +0x0C | `0x56414C44` (VALD) | 已捕获 |
| exception_count | +0x10 | **1** | 无递归 |
| trace_index | +0x14 | 16 | trace ring 已满 |
| current_el | +0x18 | 0x8 | EL2 |
| spsr | +0x20 | 0x600002C9 | EL2h |
| elr | +0x28 | **0x808B8440** | 首发现场 |
| esr | +0x30 | **0x02000000** | EC=0x00 |
| far | +0x38 | 0 | EC=0 非 abort 类，未读 FAR |
| pre_exception_sp | +0x40 | 0x80477BA0 | |
| x18 | +0x48 | 0x80477EA0 | gd 完好 |
| x29 | +0x50 | 0x80477BA0 | |
| x30 | +0x58 | 0x808B8430 | |
| pt_regs | +0x60 | 0x80477A90 | |
| expected_gd | +0x68 | 0x80477EA0 | |
| efi_gd_raw | +0x70 | 0xD70000000D000000 | BSS 垃圾，未写进 x18 |

`efi_gd_state @ 0x8090F874` = `0x45464930`（**EFI0 / UNSAVED**）——cookie 修复生效，`efi_restore_gd()` 未执行错误的 set_gd。

---

## 4. 首发现场（真正的第一次异常）

```text
ELR  = 0x808B8440  →  fdtdec_parse_phandle_with_args + 0xe0
                       808b8440:  b.lo  0x808b8410        ← 一条条件分支
ESR  = 0x02000000  →  EC=0x00 "Unknown reason", IL=1, ISS=0
FAR  = 0           →  do_sync 按 EC 判断非 abort 类，正确地未读 FAR
SPSR = 0x600002C9  →  EL2h
```

### 4.1 反汇编（异常指令上下文）

```asm
fdtdec_parse_phandle_with_args:
  ...
808b842c: bl    fdtdec_get_int        ; 取 #cells 计数
808b8430: cmn   w0, #0x1              ; x30=0x808b8430（返回地址）
808b8434: b.eq  0x808b8410            ; -1 则错误
808b8438: add   x1, x19, w0, uxtw #2  ; x1 = args + count*4
808b843c: cmp   x25, x1               ; 边界检查
808b8440: b.lo  0x808b8410            ; 越界则错误  ← 异常落在此
```

DDR 中 0x808B8440 指令字 = `0x54FFFE83`，与 ELF 完全一致（代码未被覆盖）。

### 4.2 寄存器现场（pt_regs @ 0x80477A90）

```text
x0=0x2  x1=0x80950F14  x2=0xC  x3=0x73  x4=0xC
x5=0x80967F39  x6=0xA98  x7=0x80948170  x8=0xA88
x9=0x80477AAC  x10=0x3  x11=0xA48  x12=0
x13=0x80948170  x14=0x80948170  x15=0x800811FC  x16=0x80870260
x17=0  x18=0x80477EA0(gd)  x19=0x80950F0C  x20=0x80477C38
x21=0  x22=0x808F4F60  x23=0x80948170(fdt)  x24=0
x25=0x80950F14  x26=0x5  x27=0  x28=0xA48
x29=0x80477BA0  x30=0x808B8430
```

关键：`x19=0x80950F0C`（args 数组），`x25=0x80950F14`（边界），`w0=2`（2 个 cell）。`x1 = x19 + 2*4 = 0x80950F14 = x25`，**边界检查通过**（相等，不越界）。

---

## 5. 完整调用链（FP 链逐级还原）

```
_main                                     (lr=0x8080252C = _main+0x24)
  → board_init_f                          (lr=0x8082B948 = board_init_f+0x2c)
    → initcall_run_list                   (lr=0x808AF50C = initcall_run_list+0x7c)
      → serial_init                       (lr=0x808641EC = serial_init+0x50)
        → uclass_get_device_tail          (lr=0x8083B330 = +0x1c)
          → device_probe                  (lr=0x80839BB8 = device_probe+0x60)
            → device_of_to_plat           (lr=0x80839B44 = +0x114)
              → omap_serial_of_to_plat    (lr=0x80864A34 = +0x6c)
                → clk_get_by_index_nodev  (lr=0x80837C60 = +0x30)
                  → ofnode_parse_phandle_with_args  (lr=0x8083D644 = +0x30)
                    → fdtdec_parse_phandle_with_args   ← 异常 (0x808B8440)
```

对应 trace ring 最后一条 `0x2001 (DM_BIND_ENTER)`，dev_name=`"mcu-uart0-default-pins"`——正在初始化 mcu_uart0 串口，解析其 `clocks` 属性。

---

## 6. 为什么"不是软件 bug"

1. **异常落在 `b.lo` 条件分支上**：分支指令不访问内存，不可能自己触发数据异常。ELR 指向分支 = 异常不是当前指令引起。
2. **FDT 完好**：`gd->fdt_blob = 0x80948170`，magic = `0xd00dfeed` 正常；`x19/x25` 都在 DTB 内，边界检查通过。
3. **代码未被覆盖**：DDR 指令字与 ELF 一致。
4. **ESR = EC=0x00 "Unknown reason"**：不是数据异常(0x25)、不是指令异常(0x21)、不是 BRK(0x3C)、不是 watchpoint(0x34/0x35)。这是 A72 报"无法归类的实现相关同步异常"，典型对应**内存子系统在无法定位到具体 load/store 时上报的同步错误**（DDR ECC / 互联 / 防火墙）。

---

## 7. 纠正之前的结论

旧（未打 patch）dump 中，"首发 ELR=0x80848C50 = ti_sci_probe 里的 `bl device_bind_driver`"是**误判**——那是递归几千轮后幸存下来的较老帧，不是真正的第一次。真正的第一次（本次才干净捕获）是 **serial_init → UART 时钟解析**。`ti_sci_probe` 这条线索可以放下。

---

## 8. 漂移判断

**单次干净 dump 无法判定跨次漂移**（需要 ≥2 次干净首发现场对比）。两个间接信号：

1. ELR 落在分支上 = "上报落点"与"真实故障点"已脱钩，本身是硬件类异常特征。
2. 两次 dump 的 BSS 垃圾值不同：`efi_gd` 旧 `0x696368780067746F`（"otg\0xhci"）→ 新 `0xD70000000D000000`，DDR BSS 区域内容随启动变化（旁证）。

---

## 9. 下一步定位所需信息

### P0-1：A72 RAS 错误记录寄存器（投入产出比最高）

```text
ERRIDR_EL1                ; 读一次：确认 RAS 实现 + 错误记录条数
msr ERRSELR_EL1, #i       ; 选择记录 i
mrs ERXSTATUS_EL1         ; bit31=Valid, bit30=SERR, bit29=UE
mrs ERXADDR_EL1           ; 错误地址（真实故障点）
mrs ERXMISC0_EL1 / ERXMISC1_EL1
```

若 `ERXSTATUS_EL1` Valid/UE 置位，`ERXADDR_EL1` 直接给出错误物理地址，可判断 ECC/缓存/总线错误。

### P0-2：MMU 状态

```text
SCTLR_EL2 (bit0 = M)   TTBR0_EL2 / TTBR1_EL2   TCR_EL2 / MAIR_EL2
```

`serial_init` 在 `board_init_f` 阶段，MMU 通常关闭；若关闭，异常即物理访问级外部中止（互联/防火墙/ECC）。

### P1-1：DDR 控制器 ECC 状态寄存器（MMIO，需调试器读，不在 dump 范围）

查 J784S4 DDRSS 的 ECC 错误计数/状态寄存器（UE/CE 计数）。

### P1-2：再复现一次，抓 `early_crash_record`

```text
地址 0x80908C38，长度 0x280 字节；+0x60 处 pt_regs 指针，0x110 字节
```

对比新 ELR 与本次 0x808B8440：
- 落点变了 → 硬件偶发坐实；
- 每次落在同一个 `b.lo` → 重新怀疑软件/DTB。

---

## 10. config 相关发现

```text
CONFIG_ARMV8_EA_EL3_FIRST 未开  → 外部中止在 EL2 直接处理（进 do_sync）
CONFIG_TI_SECURE_DEVICE=y        → HS 类设备，TIFS 配置防火墙
CONFIG_SOC_K3_J784S4=y
CONFIG_TARGET_J784S4_A72_EVM=y
CONFIG_DEFAULT_DEVICE_TREE="ti/k3-j784s4-evm"
CONFIG_SYS_MALLOC_F_LEN=0x8000
```

结合此前 kernel 侧 `SError code 0xbf000002`（EC=0x2F 异步外部中止），u-boot 侧 EC=0x00 同步异常与之同属**外部中止/内存错误家族**，倾向为板级硬件问题（DDR ECC/互联/防火墙），而非软件 bug。

---

## 11. 关键地址速查

| 项 | 地址 |
|---|---|
| early_crash_record | 0x80908C38 |
| efi_gd_state | 0x8090F874 |
| efi_gd | 0x80951B58 |
| gd | 0x80477EA0 |
| fdt_blob (DTB) | 0x80948170 |
| pt_regs（本次） | 0x80477A90 |
| 首发现场 ELR | 0x808B8440 |
| 复位后 attach 现场 PC | 0x808BA010 (hang+0x14) |
