华为HG8245H救砖番外篇之利用JTAG完成硬件初始化

前言

前几天使用UBoot恢复mtd分区时,因为误操作,导致flash全部被擦除。这下设备上电时连StartCode都跑不了。写内存跑StartCode都不行(外部设备没有初始化,无法访问DRAM):

> mdw 0x82000000
data abort at 0x82000000, dfsr = 0x00001008

可以看到,原本是放置StartCode的地址,现在都无法访问。折腾了几天,大致成功的利用JTAG完成硬件初步初始化,并且可以加载StartCode到内存并成功运行了。

问题解决思路

想要写内存来运行代码,就必须对内存进行初始化操作。但这个初始化操作应该都是StartCode里做的。现在StartCode都跑不起,更别说写内存了。

如果用JTAG来模拟StartCode的初始操作的话,也不太现实,毕竟100多KB的代码分析起来就够累人了,别说模拟了。但是如果能找到一个平衡点,模拟少量的操作,让硬件环境刚好够我利用来跑StartCode,这样实现还是比较容易的。

在网上查了很多关于ARM处理器复位时的流程和低级bootloader做的工作相关的资料。大致感觉有路可走:

一般对于采用非可直接寻址的存储设备(Nand Flash)来引导的话,CPU内部会有一个bootrom,bootrom在上电时会从非可直接寻址的存储设备的固定位置装载固定大小的内容到片内SRAM(比如从Nand Flash的0地址读取2KB内容到片内SRAM),然后设置pc过去并运行。这很小的一部分bootloader就会做简单的初始化操作,然后读取完整的bootloader到内存中的指定位置并运行。

逆向分析StartCode

StartCode的一开始就是ARM经典的中断向量表:

seg000:00000000 ; ---------------------------------------------------------------------------
seg000:00000000                 B               sub_5C
seg000:00000004 ; ---------------------------------------------------------------------------
seg000:00000004                 LDR             PC, =sub_820003A0
seg000:00000008 ; ---------------------------------------------------------------------------
seg000:00000008                 LDR             PC, =loc_82000400
seg000:0000000C ; ---------------------------------------------------------------------------
seg000:0000000C                 LDR             PC, =loc_82000460
seg000:00000010 ; ---------------------------------------------------------------------------
seg000:00000010                 LDR             PC, =loc_820004C0
seg000:00000014 ; ---------------------------------------------------------------------------
seg000:00000014                 LDR             PC, =loc_82000520
seg000:00000018 ; ---------------------------------------------------------------------------
seg000:00000018                 LDR             PC, =loc_82000580
seg000:0000001C ; ---------------------------------------------------------------------------
seg000:0000001C                 LDR             PC, =loc_820005E0
seg000:0000001C ; ---------------------------------------------------------------------------
seg000:00000020 off_20          DCD sub_820003A0        ; DATA XREF: seg000:00000004
seg000:00000024 off_24          DCD loc_82000400        ; DATA XREF: seg000:00000008
seg000:00000028 off_28          DCD loc_82000460        ; DATA XREF: seg000:0000000C
seg000:0000002C off_2C          DCD loc_820004C0        ; DATA XREF: seg000:00000010
seg000:00000030 off_30          DCD loc_82000520        ; DATA XREF: seg000:00000014
seg000:00000034 off_34          DCD loc_82000580        ; DATA XREF: seg000:00000018
seg000:00000038 off_38          DCD loc_820005E0        ; DATA XREF: seg000:0000001C

 

第一个中断向量就是偏移0的复位中断向量。CPU在复位时会从这里开始执行,复位中断向量直接跳到0x5C处(处理reset中断的实际代码位置)。

在StartCode的0x5C处,IDA Pro就可以直接F5了,以下为还原的伪代码(部分地方还原的有问题,手工修改过):

void sub_5C()
{
  unsigned int _R0; // r0@1
  signed int v5; // r3@1
  signed int v6; // r0@1
  signed int v7; // r1@2
  _DWORD *v8; // r2@14
  int (*v9)(); // r0@16
  void (__noreturn *v10)(); // r1@16
  int v11; // r3@17
  int v12; // r4@17
  int v13; // r5@17
  int v14; // r6@17
  int v15; // r7@17
  int v16; // r8@17
  int v17; // r9@17
  int v18; // r10@17

  //enter Supervisor mode 
  _R0 = __get_CPSR() & 0xFFFFFFE0 | 0xD3;
  __asm { MSR             CPSR_cf, R0 }

  //arm cp15 coprocessor 
  __mcr(15, 0, 0, 8, 7, 0);
  __mcr(15, 0, 0, 7, 5, 0);
  __mcr(15, 2, 0, 0, 0, 0);
  v5 = ((unsigned int)__mrc(15, 1, 0, 0, 0) >> 13) & 0x1FF;
  v6 = 0;
  do
  {
    v7 = 0;
    do
      __mcr(15, 0, (v6 << 30) | 32 * v7++, 7, 6, 2);
    while ( v7 <= v5 );
    ++v6;
  }
  while ( v6 < 4 );
  if ( __mrc(15, 0, 0, 0, 5) & 0xF )
    goto LABEL_25;
  __mcr(15, 0, __mrc(15, 0, 1, 0, 0) & 0xFFFFDFF8 | 0x802, 1, 0, 0);
  if ( !(__mrc(15, 0, 0, 0, 5) & 0xF) )
  {
    sub_6EC();
    sub_700();
    sub_710();
  }
  __mcr(15, 0, __mrc(15, 0, 1, 0, 0) | 0x1000, 1, 0, 0);
  v10A30004 = 853;
  v10A20100 |= 2u;
  sub_FAD4();
  dword_1010007C = -1;
  dword_1010008C = -1;
  dword_1010012C = -1;
  dword_10100130 = 0xFE7FFFFF;
  dword_10100138 |= 0x7Fu;
  dword_10100140 |= 0x80000000;
  if ( dword_10100800 == 0x51152100 )
  {
    if ( (dword_10100190 & 1) == 1 )
      dword_1010005C = 0x8103844D;
    dword_1010005C = 0x8103444D;
  }
  while ( (dword_10100038 & 0x10000) != 0x10000 )
    ;
  while ( (dword_10100038 & 0x40000) != 0x40000 )
    ;
  dword_1010013C = dword_1010013C & 0xFFFFFFE3 | 0x10;
  sub_FCD4();
  dword_1010013C &= 0xFFFFF3FF;
  dword_10100138 &= 0xFFDFFFFF;
  dword_10100138 &= 0xFFF7FFFF;
  dword_10100054 = 0xFFFFFFE0;
  dword_10100050 = 0x7FF00;
  dword_10100000 |= 4u;
  while ( (*v8 & 4) != 4 )
    ;
  sub_FAF4();
  sub_FBD8();
  sub_FED4();
  //判断装载地址,准备自搬移
  v9 = sub_0;
  v10 = sub_82000000;
  if ( (char *)sub_0 != (char *)sub_82000000 )
  {
    do
    {
      v11 = *(_DWORD *)v9;
      v12 = *((_DWORD *)v9 + 1);
      v13 = *((_DWORD *)v9 + 2);
      v14 = *((_DWORD *)v9 + 3);
      v15 = *((_DWORD *)v9 + 4);
      v16 = *((_DWORD *)v9 + 5);
      v17 = *((_DWORD *)v9 + 6);
      v18 = *((_DWORD *)v9 + 7);
      v9 = (int (*)())((char *)v9 + 32);
      *(_DWORD *)v10 = v11;
      *((_DWORD *)v10 + 1) = v12;
      *((_DWORD *)v10 + 2) = v13;
      *((_DWORD *)v10 + 3) = v14;
      *((_DWORD *)v10 + 4) = v15;
      *((_DWORD *)v10 + 5) = v16;
      *((_DWORD *)v10 + 6) = v17;
      *((_DWORD *)v10 + 7) = v18;
      v10 = (void (__noreturn *)())((char *)v10 + 32);
    }
    while ( (signed int)v9 <= (signed int)&unk_1F1B4 );
    if ( dword_10100800 != 0x51152100 )
LABEL_21:
      JUMPOUT(&loc_820002C8);
    if ( __mrc(15, 0, 0, 0, 5) & 0xF )
    {
LABEL_25:
      while ( 3538 != dword_10100120 )
        ;
      goto LABEL_21;
    }
  }
  JUMPOUT(&loc_82000304);
}

可以看出,在

v9 = sub_0;
v10 = sub_82000000;

之后就开始代码的自搬移了。其中v9是程序装载的位置,v10是StartCode应该被放置的地址。

也就是说,只要通过JTAG完成这两句代码之前StartCode所做的操作,就可以使用JTAG访问外部RAM了(起始地址大约在0x80000000)。

使用TCL脚本模拟实现初始化操作

好在OpenOCD支持tcl脚本,大概熟悉了一下tcl的语法,并结合逆向的数据,写了个模拟初始化操作的脚本:

#
# Hisilicon SD5115 (T?)
#
# Author : CserSoft
# Version : 1.2.2
#

transport select jtag

if { [info exists CHIPNAME] } {
    set  _CHIPNAME $CHIPNAME
} else {
    set  _CHIPNAME sd5115
}

if { [info exists CPUTAPID] } {
    set _CPU_TAPID $CPUTAPID
} else {
    set _CPU_TAPID 0x4ba00477
}

if { [info exists ENDIAN] } {
    set _ENDIAN $ENDIAN
} else {
    # this defaults to a bigendian
    set _ENDIAN little
}

if { [info exists ETB_TAPID] } {
    set _ETB_TAPID $ETB_TAPID
} else {
    set _ETB_TAPID 0x410CF231
}

jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPU_TAPID

# jtag newtap $_CHIPNAME etb -irlen 4 -expected-id $_ETB_TAPID

set _TARGETNAME $_CHIPNAME.cpu

target create $_TARGETNAME cortex_a -endian $_ENDIAN -chain-position $_TARGETNAME

# etm_dummy config $_TARGETNAME
# etb config $_TARGETNAME $_CHIPNAME.etb

proc sd5115_dbginit { target } {
    cortex_a dbginit
}

proc getmem32 { addr } {
    mem2array atmp 32 $addr 1
    return [lindex $atmp 1]
}

proc setmem32 { addr value } {
    mww phys $addr $value 1
}

proc andmem32 { addr value } {
    set vmem [getmem32 $addr]
    return [expr $vmem & $value]
}

proc andmem32w { addr value } {
    set vmem [expr [getmem32 $addr] & $value]
    mww phys $addr $vmem 1
    return $vmem
}

proc ormem32 { addr value } {
    set vmem [getmem32 $addr]
    return [expr $vmem | $value]
}

proc ormem32w { addr value } {
    set vmem [expr [getmem32 $addr] | $value]
    mww phys $addr $vmem 1
    return $vmem
}


proc sd5115_startcode_offset_0x6EC { } {
    andmem32w 0x10180000 0xFFFFFFFE
}

proc sd5115_startcode_offset_0x700 { } {
    mww phys 0x1018000C 0xFFFFFFFF 1
}

proc sd5115_startcode_offset_0x710 { } {
    ormem32w 0x10180054 0xFF
    ormem32w 0x10180000 0x1
}

proc sd5115_startcode_offset_0xFAD4 { } {
    setmem32 0x10100144 [expr [andmem32 0x10100144 0xFFF803FF] | 0x400]
}

proc sd5115_startcode_offset_0xFAF4 { } {
    set vcpuid [getmem32 0x10100800]
    
    if { $vcpuid == 0x51151100 } {
        ormem32w    0x13000000 0x80000
        ormem32w    0x10106008 0xC0
        ormem32w    0x10106008 0x300
    } elseif { $vcpuid == 0x51152100 } {
        ormem32w    0x13000000 0x60000
        ormem32w    0x10108008 0xF0
    } else {
        ormem32w    0x130001C8 0x100
        ormem32w    0x10106008 0xC00
        andmem32w   0x13000000 0xFFFFFFFB
        andmem32w   0x130001C8 0xFFFFFFDF
        ormem32w    0x10106008 0x3000
        andmem32w   0x13000000 0xFFFDFFFF
        andmem32w   0x130001C8 0xFFFFFFBF
    }
}

proc sd5115_startcode_offset_0xFBD8 { } {
    set vcpuid [getmem32 0x10100800]
    
    if { $vcpuid != 0x51151100 } {
        if { $vcpuid == 0x51152100 } {
            setmem32    0x10400500 0x1FFF800
            andmem32w   0x10100134 0xFFFFFFFC
            andmem32w   0x10107008 0xDDFFFFFF
            ormem32w    0x10107004 0x22000000
            ormem32w    0x10107000 0x22000000
            andmem32w   0x10108008 0xFFF7FFFF
            ormem32w    0x10108004 0x80000
            ormem32w    0x10108000 0x80000
            andmem32w   0x10100144 0x3FFFFFFF
        } else {
            setmem32    0x10400500 0x1FFF800
            andmem32w   0x10100134 0xFFFFFFFC
            ormem32w    0x10107004 0x18000
            andmem32w   0x10107000 0xFFFE7FFF
            ormem32w    0x10107000 0x18000
            andmem32w   0x1300016C 0xFFFFFFFC
        }
    }
}

proc sd5115_startcode_offset_0xFCD4 { } {
    set vcpuid [getmem32 0x10100800]
    
    if { $vcpuid == 0x51151100 } {
        andmem32w   0x1010012C 0xFFBFFFFF
        andmem32w   0x10100138 0xFFFFFFBF
        ormem32w    0x10100080 0x9
        andmem32w   0x1010013C 0xFFFFEFFF
        setmem32    0x1010005C 0x81020248
        
        while { [andmem32 0x10100038 0x10000] != 0x10000 } {sleep 1}
        
        ormem32w 0x1010007C 0x9
        ormem32w 0x10100148 0x2
        ormem32w 0x1010012C 0x400000
        ormem32w 0x10100138 0x40
        
    } elseif { $vcpuid == 0x51152100 } {
        if { [andmem32 0x10100190 1] == 1 } {
            andmem32w   0x1010012C 0xFFBFFFFF
            andmem32w   0x10100138 0xFFFFFFBF
            ormem32w    0x10100080 0x9
            andmem32w   0x10100144 0xFEFFFFFF
            andmem32w   0x10100140 0xFFFFCFFF
            ormem32w    0x10100140 0x40000000
            setmem32    0x10100074 0x81028249
            
            while { [andmem32 0x10100038 0x40000] != 0x40000 } {sleep 1}

            ormem32w 0x1010007C 0x9
            ormem32w 0x10100148 0x2
            ormem32w 0x1010012C 0x400000
            ormem32w 0x10100138 0x40
        } else {
            while { [andmem32 0x10100038 0x20000] != 0x20000 } {sleep 1}
        }
        
    } else {
        andmem32w   0x1010012C 0xFFBFFFFF
        andmem32w   0x10100138 0xFFFFFFBF
        ormem32w    0x10100080 0x9
        setmem32    0x1010011C 0x81028648

        while { [andmem32 0x10100038 0x20000] != 0x20000 } {sleep 1}

        ormem32w 0x1010007C 0x9
        ormem32w 0x10100148 0x2
        ormem32w 0x1010012C 0x400000
        ormem32w 0x10100138 0x40
    }
}

proc sd5115_startcode_offset_0xFED4 { } {
    set vcpuid [getmem32 0x10100800]
    
    if { $vcpuid == 0x51151100 } {
        setmem32 0x10102010 1
        setmem32 0x1010201C 0x8DF40630
        setmem32 0x10102020 0x10184
        setmem32 0x1010202C 0x132
        setmem32 0x10102040 0x80000000
        setmem32 0x10102050 0x62330A08
        setmem32 0x10102054 0x7F525616
        setmem32 0x1010205C 0x4BE58352
        setmem32 0x101020F4 1
        setmem32 0x10102058 0x6230A000
        setmem32 0x10102004 0

        while { [andmem32 0x10102000 4] != 0 } { sleep 1 }

        setmem32 0x10102404 0x80000000
        
        while { [andmem32 0x10102410 1] != 1 } { sleep 1 }
          
        setmem32 0x10102418 0xDC000
        setmem32 0x10102584 0x5D
        setmem32 0x1010240C 0x3008401
        setmem32 0x10102444 0x48B
        setmem32 0x10102448 0x51106644
        setmem32 0x1010244C 0x1A81629A
        setmem32 0x10102450 0x100220C8
        setmem32 0x10102454 0x1520
        setmem32 0x10102458 6
        setmem32 0x1010245C 0
        setmem32 0x10102460 0
        setmem32 0x101025C0 0x44000887
        setmem32 0x10102440 0xF008003E
        setmem32 0x10102468 0x1001541
        setmem32 0x10102404 0xFFF3
        
        while { [andmem32 0x10102410 0x80000FFF] != 0x80000FFF } { sleep 1 }
        
        setmem32 0x10102058 0x6230A05F
        setmem32 0x10102020 0x410185
        setmem32 0x1010201C 0x8DF40630
        setmem32 0x10102200 0x305133
        setmem32 0x10102204 0x3062CC
        
    } elseif { $vcpuid == 0x51152100 } {
        if { [andmem32 0x10100190 1] == 1 } {
            setmem32 0x10102010 1
            setmem32 0x1010201C 0x80000600
            setmem32 0x10102020 0x584
            setmem32 0x1010202C 0x142
            setmem32 0x10102040 0x80000000
            setmem32 0x10102050 0x63440E0A
            setmem32 0x10102054 0xFF526720
            setmem32 0x10102058 0x6240A000
            setmem32 0x1010205C 0xFFDFF5F2
            setmem32 0x101020F4 0x21
            setmem32 0x101020AC 0x3000501
            setmem32 0x10102004 0

            while { [andmem32 0x10102000 4] != 0 } { sleep 1 }

            setmem32 0x10102404 0x80000000

            while { [andmem32 0x10102410 1] != 1 } { sleep 1 }

            setmem32 0x10102418 0x5C000
            setmem32 0x1010248C 0xF01E78
            setmem32 0x1010241C 0x1F40FA10
            setmem32 0x10102420 0x61A808CA
            setmem32 0x10102428 0xC83D090
            setmem32 0x1010242C 0x1F4186A0
            setmem32 0x10102444 0x48B
            setmem32 0x10102448 0x6D538844
            setmem32 0x1010244C 0x22820282
            setmem32 0x10102450 0x1002EA00
            setmem32 0x10102454 0x1930
            setmem32 0x10102458 0x42
            setmem32 0x1010245C 8
            setmem32 0x10102460 0
            setmem32 0x10102464 0x210000
            setmem32 0x10102468 0x210035C3
            setmem32 0x10102584 0x2D
            setmem32 0x101025C0 0x44000E81
            setmem32 0x10102600 0x44000E81
            setmem32 0x10102440 0xF000603E
            setmem32 0x10102404 0xFFF3

            while { [andmem32 0x10102410 1] != 1 } { sleep 1 }

            setmem32 0x10102058 0x6240A079
            setmem32 0x10102200 0x304132
            setmem32 0x10102204 0x306132
            setmem32 0x10102208 0x304066
            setmem32 0x10102210 0x306132
        } else {
            setmem32 0x10102010 1
            setmem32 0x1010201C 0x80000601
            setmem32 0x10102020 0x580
            setmem32 0x1010202C 0x142
            setmem32 0x10102040 0x80000000
            setmem32 0x10102050 0xC466150F
            setmem32 0x10102054 0xFF545540
            setmem32 0x10102058 0x84610000
            setmem32 0x1010205C 0xFFDFF4F4
            setmem32 0x101020F4 0x21
            setmem32 0x101020AC 0x3000501
            setmem32 0x10102004 0

            while { [andmem32 0x10102000 4] != 0 } { sleep 1 }

            setmem32 0x10102404 0x80000000

            while { [andmem32 0x10102410 1] != 1 } { sleep 1 }

            setmem32 0x10102418 0x5C000
            setmem32 0x1010248C 0xF01860
            setmem32 0x1010241C 0x1900C810
            setmem32 0x10102420 0x4E200708
            setmem32 0x10102428 0xA030D40
            setmem32 0x1010242C 0x19013880
            setmem32 0x10102444 0x48B
            setmem32 0x10102448 0x550F6644
            setmem32 0x1010244C 0x22820202
            setmem32 0x10102450 0x1002EA00
            setmem32 0x10102454 0x1510
            setmem32 0x10102458 0x42
            setmem32 0x1010245C 0
            setmem32 0x10102460 0
            setmem32 0x10102464 0x210000
            setmem32 0x10102468 0x210035C3
            setmem32 0x10102584 0x2D
            setmem32 0x101025C0 0x44000E81
            setmem32 0x10102600 0x44000E81
            setmem32 0x10102440 0xF008603E
            setmem32 0x10102404 0xFFF3

            while { [andmem32 0x10102410 1] != 1 } { sleep 1 }

            setmem32 0x10102058 0x846100C3
            setmem32 0x10102200 0x304132
            setmem32 0x10102204 0x306132
            setmem32 0x10102208 0x304066
            setmem32 0x10102210 0x306132
        }
    } else {
        setmem32 0x10102010 1
        setmem32 0x1010201C 0xE92E0601
        setmem32 0x10102020 0x1F180
        setmem32 0x1010202C 0x132
        setmem32 0x10102040 0x80000000
        setmem32 0x10102050 0xC466130E
        setmem32 0x10102054 0xFF535625
        setmem32 0x1010205C 0x7E58484
        setmem32 0x101020F4 1
        setmem32 0x10102058 0x74511000
        setmem32 0x101020AC 0x3000501
        setmem32 0x10102004 0
        
        while { [andmem32 0x10102000 4] != 0 } { sleep 1 }
        
        setmem32 0x10102404 0x80000000
        
        while { [andmem32 0x10102410 1] != 1 } { sleep 1 }
        
        setmem32 0x10102418 0xDC000
        setmem32 0x1010240C 0x3008401
        setmem32 0x10102444 0x48B
        setmem32 0x10102448 0x4D0E6644
        setmem32 0x1010244C 0x1A812A30
        setmem32 0x10102450 0x1001A0C8
        setmem32 0x10102454 0x1320
        setmem32 0x10102458 0x42
        setmem32 0x1010245C 0
        setmem32 0x10102460 0
        setmem32 0x10102468 0x11001547
        setmem32 0x101025C0 0x44000887
        setmem32 0x10102600 0x44000E81
        setmem32 0x10102440 0xF008003E
        setmem32 0x10102584 0x1D
        setmem32 0x10102404 0xFFF3
        
        while { [andmem32 0x10102410 0x80000FFF] != 0x80000FFF } { sleep 1 }
        
        setmem32 0x10102058 0x7450F09E
        setmem32 0x10102020 0x40EF01
        setmem32 0x101020F8 0
        setmem32 0x10102200 0x305133
        setmem32 0x10102204 0x306266
        setmem32 0x10102208 0x306066
        setmem32 0x1010220C 0
        setmem32 0x1010201C 0xB9D60601
    }
}

proc sd5115_hwinit { } {
    halt
    
    #enter Supervisor mode
    reg cpsr 0x1D3
    
    arm mcr 15 0 8 7 0 0
    arm mcr 15 0 7 5 0 0
    arm mcr 15 2 0 0 0 0
    
    
    set v5 [expr ([arm mrc 15 1 0 0 0] >> 13) & 0x1ff]
    set v6 0
    
    
    while {$v6 < 4} {
        set v7 0
        
        while {$v7 <= $v5} {
            set vtmp [expr ($v6 << 30) | 32 * $v7]
            set v7 [incr $v7]
            
            arm mcr 15 0 7 6 2 $vtmp
        }
        
        set v6 [incr $v6]
    }
    
    if { [expr [arm mrc 15 0 0 0 5] & 0xf] != 0} {
        echo "Error 1 !"
        return
    }
    
    arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 0 0 1] & 0xFFFFDFF8 | 0x802]
    
    if { [expr [arm mrc 15 0 0 0 5] & 0xf] != 0} {
        sd5115_startcode_offset_0x6EC
        sd5115_startcode_offset_0x700
        sd5115_startcode_offset_0x710
    }
    
    arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] | 0x1000]
    
    setmem32 0x10A30004 0x00000355
    
    ormem32w 0x10A20100 0x2
    
    sd5115_startcode_offset_0xFAD4 
    
    setmem32 0x1010007C 0xFFFFFFFF
    setmem32 0x1010008C 0xFFFFFFFF
    setmem32 0x1010012C 0xFFFFFFFF
    setmem32 0x10100130 0xFE7FFFFF
    
    ormem32w 0x10100138 0x7F
    ormem32w 0x10100140 0x80000000

    set vcpuid [getmem32 0x10100800]
    
    if { $vcpuid == 0x51152100 } {
        if { [expr [getmem32 0x10100190] & 1] == 1 } {
            mww phys 0x1010005C 0x8103844D 1
        }
        
        mww phys 0x1010005C 0x8103444D 1
    }
    
    while { [andmem32 0x10100038 0x10000] != 0x10000 } {sleep 1}
    while { [andmem32 0x10100038 0x40000] != 0x40000 } {sleep 1}
    
    setmem32 0x1010013C [expr [andmem32 0x1010013C 0xFFFFFFE3] | 0x10]
    
    sd5115_startcode_offset_0xFCD4
    
    andmem32w 0x1010013C 0xFFFFF3FF
    andmem32w 0x10100138 0xFFDFFFFF
    andmem32w 0x10100138 0xFFF7FFFF
    setmem32 0x10100054 0xFFFFFFE0
    setmem32 0x10100050 0x7FF00
    ormem32w 0x10100000 0x4
    
    while { [andmem32 0x10100000 0x4] != 0x4 } {sleep 1}
    
    sd5115_startcode_offset_0xFAF4
    sd5115_startcode_offset_0xFBD8
    sd5115_startcode_offset_0xFED4
    
    echo "Hardware initialization is complete!"
}

$_TARGETNAME configure -event reset-assert-post "sd5115_dbginit $_TARGETNAME"

# init
# dap apsel 1

使用JTAG完成基本硬件初始化

为了确保初始化准确无误,需要保证CPU上电时完全无法找到可以引导的代码。

因为我之前清空flash时,也曾尝试立刻刷回StartCode,可惜不知什么原因,只写入了2KB的StartCode,这样仍然无法完成基本的初始化。但不清楚这2KB的代码完成了哪些操作,所以一个办法就是先将flash的CE#(CE#这种后面带#字的引脚,都是低电平有效)与3.3V短接(最好是能与输出3.3V的GPIO短接,与3.3V的VCC短接电流可能较大,不知是否有不良影响),再给板子上电。HG8245H的CE#引脚在板子背面电源led附近有个上拉电阻R1542,可以在这里短接。

CPU上电后,在OpenOCD的telnet里执行上面脚本提供的sd5115_hwinit函数,等看到输出

Hardware initialization is complete!

字样的提示后,把之前dump出来的StartCode写入内存并运行:

halt ; load_image binary/mtd0.bin 0x82000000 ; resume 0x82000000

这时应该可以看见UART里输出了久违的StartCode信息:

HuaWei StartCode 2012.02 (R13C10 Apr 22 2014 – 18:06:02)

NAND: Nand(Hardware): 128 MiB
startcode select the uboot to load
the high RAM is :8080103c
startcode uboot boot count:-1
Slave struct initializtion success!!
Use the UbootA to load first
Start from UbootA ERROR, Change to UbootB
Both UbootA and UbootB are wrong, load it by JTAG!

补充:

新版本的OpenOCD配置文件见:https://github.com/csersoft/hi_sd5115_openocd_config

Print Friendly, PDF & Email

《华为HG8245H救砖番外篇之利用JTAG完成硬件初始化》有18条留言

  1. 意思是用您的方法用jtag连上猫(确认无误),初始化cpu,加载startcode,加载uboot,整个过程ttl都没任何信息输出。但调试多次,偶尔1次2次会有输出。换不同TTL小板和不同光猫试过都这样。

    回复
  2. 用ft2232h连接8245c2(与H硬件、电路完全一样),pl2303(或ch341a)连接8245C2的TTL,8245C2的nand已拆下,给8245C2上电,cmd下运行“bin-x64\openocd.exe -s ..\scripts -f ft2232h.cfg -f hi_sd5115_jtag.cfg”(我的配置文件与openocd位于同一目录),正确识别出cpu并等待命令并显示“Info : sd5115.cpu: hardware has 6 breakpoints, 4 watchpoints”,另一cmd窗口下telnet 127.0.0.1 14444,执行sd5115_hwinit初始cpu成功,加载startcode“halt ; load_image mtd0.bin 0x82000000 ; resume 0x82000000(mtd0.bin位于上述同一目录下),显示下载成功,但这是TTL没任何输出,再加载uboot”halt ; load_image 8245H_R16_UB.BIN 0x81F00000 ; resume 0x81F00000“(也是同一目录下),显示下载成功,但TTL也没有输出结果。试过多次(所有步骤重新来),偶尔会有一两次TTL会输出。

    回复
    • 正常情况下,加载成功sc之后肯定会有输出的,没有输出就不要继续加载uboot了。
      hi_sd5115_jtag.cfg是否是github上那个最新的?是最新的话,执行sd5115_help查看示例操作,文章中的命令可能过时了。

      回复
    • proc sd5115_help { } {
      echo “Usage 1:”
      echo ” *Step1: {sd5115_hwinit}”
      echo ” *Step2: {sd5115_loadsc mtd0.bin}”
      echo ” Step3: {sd5115_enter_svc_mode}”
      echo ” *Step4: {sd5115_goto_entry} or {sd5115_goto_continue}”
      echo ” !Note!: {sd5115_goto_continue} is not recommended”
      echo ” ”
      echo “Usage 2:”
      echo ” *Step1: {sd5115_init_dram}”
      echo ” *Step2: {sd5115_loadsc mtd0.bin}”
      echo ” Step3: {sd5115_enter_svc_mode}”
      echo ” *Step4: {sd5115_goto_entry} or {resume 0x82000000}”
      echo ” ”
      }

      回复
  3. 按着sd5115_help 的步骤来,执行到sd5115_goto_entry这上一步显示“ Can’t resume (1)!”,我看了一下sd5115_goto_entry代码,是要满足getmem32 0x10100800] != 0x51152100 才会 resume ,但我看了一下getmem32 0x10100800的返回值就是0x51152100,造成不执行 resume 。请问会是什么原因造成的呢?

    回复
  4. 上述是按Usage 1来的,按Usage 2来做的话,执行到sd5115_goto_entry也是返回Can’t resume ,但如果执行resume 0x82000000,没显示结果就完成了,TTL也没输出。

    回复
  5. sd5115_hwinit
    sd5115.cpu rev 1, partnum c09, arch f, variant 4, implementor 41
    sd5115.cpu cluster 0 core 0 multi core
    target halted in ARM state due to debug-request, current mode: Abort
    cpsr: 0x000001d7 pc: 0x0000000c
    MMU: disabled, D-Cache: disabled, I-Cache: disabled
    Data fault registers DFSR: 00001897, DFAR: 47298f08
    Instruction fault registers IFSR: 00001008, IFAR: ff3448e4
    background polling: on
    TAP: sd5115.cpu (enabled)
    target halted in ARM state due to debug-request, current mode: Abort
    cpsr: 0x000001d7 pc: 0x0000000c
    MMU: disabled, D-Cache: disabled, I-Cache: disabled
    Data fault registers DFSR: 00001897, DFAR: 47298f08
    Instruction fault registers IFSR: 00001008, IFAR: ff3448e4
    cpsr (/32): 0x000001D3
    Info: (arm mrc 15 0 0 0 5) & 0xf == 0 .
    Info: call offset 0x6EC .
    Info: call offset 0x700 .
    Info: call offset 0x710 .
    Info: call offset 0xFAD4 .
    Info: call offset 0xFCD4 .
    Info: call offset 0xFAF4 .
    Info: call offset 0xFBD8 .
    Info: call offset 0xFED4 (init dram).
    Info: init dram…
    Hardware initialization is complete!
    sd5115_loadsc mtd0.bin
    127412 bytes written at address 0x82000000
    downloaded 127412 bytes in 0.343752s (361.964 KiB/s)
    sd5115_enter_svc_mode
    cpsr (/32): 0x000001D3
    sd5115_enter_svc_mode
    cpsr (/32): 0x000001D3
    sd5115_goto_entry
    Warn: Can’t resume (1)!
    sd5115_goto_continue
    Warn: Can’t resume (2)!
    getmem32 0x10100800
    1360339200
    expr [arm mrc 15 0 0 0 5] & 0xf
    0

    回复

留下评论

17 − 10 =

*

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

%d 博主赞过: