1. 程式人生 > >LPC824 ROM-bootloader反彙編分析

LPC824 ROM-bootloader反彙編分析

1 ROM-bootloader反彙編分析

在Keil中(IAR暫不能實現,其他IDE未曾嘗試,本部分內容集中在對程式碼分析上,無需對工具軟體進行過多考慮)取消Option的Debug標籤頁上的“Run to main”選項,並且在Setting中選擇Stop after reset,這樣進入除錯介面後就在bootloader起始處停止,可以分析ROM中的bootloader的彙編程式碼流程。

wps2075.tmp[10]

wps2095.tmp[6]35  LPC824的ROM-Bootloader除錯設定

ROM位於0x1FFF0000 -- 0x1FFF3000之間,共12KB的ROM,包括了bootloader、ROM-API等。

wps20A6.tmp[6]

35

  LPC824的ROM、RAM位置對映圖

進入除錯介面或者除錯時按下wps20A7.tmp[6]RST按鈕,則停留在booloader的第一條程式碼,同時在Memory視窗修改地址0x0和0x1FFF0000,內容不變,可見覆位後的0x1FFF0000位置的ROM同樣對映到了0x0地址處(經過對比,暫時推測只是前面512Byte的內容對映到0x0-0x1FF地址處,從0x200開始依然為使用者的Flash程式碼)。

wps20A8.tmp[6]

注意ARM的位元組順序是小尾端(little-endian),以及PC最後一位必須為1(表示為thumb模式)。根據ARM的啟動邏輯,SP和PC分別初始化為0x0和0x04地址處的兩個32bit(4Byte)的內容,分別是0x10000FFC和0x1FFF0008,因為ARM的邏輯是0x08和0x0C地址處的內容則是NMI和HardFault兩個中斷服務里程的地址。

__Vectors       DCD     __initial_sp              ; Top of Stack

                DCD     Reset_Handler             ; Reset Handler

                DCD     NMI_Handler               ; NMI Handler

                DCD     HardFault_Handler         ; Hard Fault Handler

可知因此此時SP=0x10000FFC為SRAM0的最頂端,PC=0x1FFF0008為第一條指令地址。

wps20B9.tmp[6]

35  LPC824的ROM-Bootloader啟動除錯介面

從上圖看出未使用NMI,因為LPC824的NMI中斷使用 SYSCON 模組中的 NMISRC 暫存器選擇一個外設中斷作為 ARM Cortex-M0+ 核心 NMI 中斷的源,在bootloader中不使用,因此NMI_Handler不需要,直接跳轉執行到@0x1FFF000C的內容即0x1FFF0011地址處。

0x1FFF0008 4A00      LDR      r2,[pc,#0]  ; @0x1FFF000C

0x1FFF000A 4710      BX       r2

而0x1FFF000C處的內容也剛好是HardFault_Handler的執行地址,內容同樣是0x1FFF0011。因此實際程式碼執行結果是在0x1FFF0011處。因此HardFault_Handler也是執行0x1FFF0011的程式碼。(實際應該是ROM以確保程式碼無缺陷,不使用HardFault_Handler)。

接下來是讀取0x1FFF0064和0x1FFF0068處的內容,並存放在r2和r3暫存器中,r3的內容為0x1FFF0078,這是一個ROM中的地址,該地址儲存的內容為0x000002FC,即使用者程式碼CRP的地址,再讀取該地址的內容,即可讀取使用者程式碼的CRP值,驗證CRP1/2/3等級。

0x1FFF0010 4A14      LDR      r2,[pc,#80] ; @0x1FFF0064

0x1FFF0012 4B15      LDR      r3,[pc,#84] ; @0x1FFF0068

0x1FFF0014 681B      LDR      r3,[r3,#0x00]

0x1FFF0016 4D16      LDR      r5,[pc,#88] ; @0x1FFF0070

0x1FFF0018 682D      LDR      r5,[r5,#0x00]

0x1FFF001A 4E16      LDR      r6,[pc,#88] ; @0x1FFF0074

0x1FFF001C 6836      LDR      r6,[r6,#0x00]

0x1FFF001E 681C      LDR      r4,[r3,#0x00]

0x1FFF0020 42AC CMP      r4,r5

0x1FFF0022 D001      BEQ      0x1FFF0028

0x1FFF0024 42B4 CMP      r4,r6

0x1FFF0026 D101      BNE      0x1FFF002C

0x1FFF0028 4C10      LDR      r4,[pc,#64] ; @0x1FFF006C

0x1FFF002A 6824      LDR      r4,[r4,#0x00]

0x1FFF002C 6014 STR      r4,[r2,#0x00]

很顯然,要對比CRP跟CRP1/2/3進行比較,首先讀取當前使用者程式碼的CRP值以及常數CRP1/3的值。之後比較CRP值與CRP3和CRP1,有一個相同則跳轉到0x1FFF0028,否則跳轉到0x1FFF002C,上述執行後的的效果如下:

wps20BA.tmp[6]

35  LPC824的ROM-Bootloader的CRP1/3對比後條件執行

對比成功與否的後果為是否執行0x1FFF0028的程式碼,如果相同則執行,該程式碼是將0x1FFF006C處儲存的地址(該地址為0x1FFF007C)的值(該值為0x87654321)載入到r4。否則r4保持原樣即使用者程式碼的CRP值,然後將r4儲存到r2暫存器值作為地址的位置,r2內容為0x400483F0,該地址是SYSCON的暫存器地址空間,在DEVICE_ID暫存器之前,但是資料手冊中沒有解釋該地址暫存器的作用,根據bootloader流程圖,推測是對除錯進行使能。

wps20CA.tmp[6]

wps20CB.tmp[6]

35  LPC824的ROM-Bootloader儲存CRP值到0x400483F0所在的位置

接下來程式碼是:

0x1FFF002E 4B08      LDR      r3,[pc,#32] ; @0x1FFF0050

0x1FFF0030 681A      LDR      r2,[r3,#0x00]

0x1FFF0032 4C08      LDR      r4,[pc,#32] ; @0x1FFF0054

0x1FFF0034 8824      LDRH     r4,[r4,#0x00]

0x1FFF0036 4D08      LDR      r5,[pc,#32] ; @0x1FFF0058

0x1FFF0038 882D      LDRH     r5,[r5,#0x00]

0x1FFF003A 42AC CMP      r4,r5

0x1FFF003C D001      BEQ      0x1FFF0042

0x1FFF003E 4A07      LDR      r2,[pc,#28] ; @0x1FFF005C

0x1FFF0040 6812      LDR      r2,[r2,#0x00]

0x1FFF0042 4695 MOV sp,r2

通過讀取0x1FFF0054和0x1FFF0058的內容作為地址(分別是0x0C00013C和0x1FFF008C),將這兩個地址的內容讀入r4和r5,然後對比r4和r5,如果相同則略過0x1FFF003E,直接跳轉到0x1FFF0042,因此這段程式碼的意義是通過對比0x0C00013C(Reserved區域)和0x1FFF008C地址處(ROM中的常量)的值,來決定是否執行0x1FFF003E這兩行程式碼,本次例程的結果是兩個地址的值都是0x0000C0FA,因此跳過程式碼。

而這行程式碼執行與否的差別則是決定r2的內容是0x1FFF0050處內容作為地址(該地址為0x0C000118)的值還是0x1FFF005C處內容作為地址(該地址為0x1FFF0088)的值,經過修改PSR的Z標誌改變CMP指令的結果,可以看到r2的值變化為0x100003FF或者0x10001FFF,然後將r2儲存到sp暫存器當中,可見其功能是修改ROM-Bootloader執行的堆疊地址。推測0x0C00013C地址處的值可能是某種ROM版本或者晶片die版本的資訊?

最後跳轉到0x1FFF0060儲存的內容做為新的PC執行地址(新的PC執行地址為0x1FFF0269,注意PC最後一位必須為1表示為thumb模式)。

0x1FFF0044 4A06      LDR      r2,[pc,#24] ; @0x1FFF0060

0x1FFF0046 4710 BX       r2

跳轉到0x1FFF0268之後,程式碼如下:

0x1FFF0268 B510      PUSH     {r4,lr}

0x1FFF026A 4A5B      LDR      r2,[pc,#364] ; @0x1FFF03D8

0x1FFF026C 495B      LDR      r1,[pc,#364] ; @0x1FFF03DC

0x1FFF026E 8810      LDRH     r0,[r2,#0x00]

0x1FFF0270 4288 CMP      r0,r1

0x1FFF0272 D000      BEQ      0x1FFF0276

0x1FFF0274 E7FE      B        0x1FFF0274

0x1FFF0276 485B      LDR      r0,[pc,#364] ; @0x1FFF03E4

儲存r4和lr到堆疊,然後讀取0x1FFF03D8處的內容作為地址(該地址為0x0C00013C,Reserved區域)的值,儲存到r0,與0x1FFF03DC處的內容(ROM中的常量)儲存到r1比較,如果不相等則永遠停留在以下這條語句上。

0x1FFF0274 E7FE      B        0x1FFF0274

本例程測試後的r0與r1的內容都是0x0000C0FA,與前面的判斷內容相同,懷疑是進行另一種版本對比?執行效果如下:

wps20DC.tmp[6]

35  LPC824的ROM-Bootloader對比版本資訊?

接下來是多次的讀取和寫入,從0x0C000100附近地址空間中讀取,並寫入地址空間大約都在0x40048000--0x400483FFSYSCON地址空間,,0x0C000100區域為Reserved,推測調製TRIM資料等,後續詳細分析,TODO

0x1FFF0276 485B      LDR      r0,[pc,#364] ; @0x1FFF03E4        ; r0 = [0x1FFF03E4] = 0x400483C0

0x1FFF0278 4959      LDR      r1,[pc,#356] ; @0x1FFF03E0        ; r1 = [0x1FFF03E0] = 0x12345678

0x1FFF027A 6101 STR      r1,[r0,#0x10] ; [0x400483D0] <= 0x123456678,SYSCON中未明確暫存器。

0x1FFF027C 495A      LDR      r1,[pc,#360] ; @0x1FFF03E8        ; r1 = [0x1FFF03E8] = 0x0C000130

0x1FFF027E 680B      LDR      r3,[r1,#0x00] ; r3 = [0x0C000130] = 0

0x1FFF0280 4946      LDR      r1,[pc,#280] ; @0x1FFF039C        ; r1 = [0x1FFF039C] = 0x40048200

0x1FFF0282 39C0      SUBS     r1,r1,#0xC0 ; r1 = r1 - 0xC0 = 0x40048140

0x1FFF0284 620B STR      r3,[r1,#0x20] ; [r1 + 0x20] = [0x40048160] = 0  SYSCON中未明確暫存器。

0x1FFF0286 4B59      LDR      r3,[pc,#356] ; @0x1FFF03EC        ;

0x1FFF0288 681B      LDR      r3,[r3,#0x00] ;

0x1FFF028A 624B STR      r3,[r1,#0x24] ;

; [r1 + 0x24] = [0x40048164] = r3 = [[0x0C000134] + 0x00] = 0   ; SYSCON中未明確暫存器。

0x1FFF028C 2100 MOVS     r1,#0x00 ; r1 = 0

0x1FFF028E 6101 STR      r1,[r0,#0x10] ; [r0 + 0x10] = [0x400483D0] = 0 SYSCON中未明確暫存器。

; [r0 + 0x3C] = [0x400483D0] = r1 = 0   ; SYSCON中未明確暫存器。

0x1FFF0290 4957      LDR      r1,[pc,#348] ; @0x1FFF03F0        ;

0x1FFF0292 6809      LDR      r1,[r1,#0x00] ;

0x1FFF0294 6381 STR      r1,[r0,#0x38] ;

; [r0 + 0x38] = [0x400483F8] = r1 = [[0x1FFF03F0] + 0x00] = [0x0C00010C] = 0x00008241   ; SYSCON.DEVICE_ID

0x1FFF0296 4957      LDR      r1,[pc,#348] ; @0x1FFF03F4        ;

0x1FFF0298 6809      LDR      r1,[r1,#0x00] ;

0x1FFF029A 63C1 STR      r1,[r0,#0x3C] ;

; [r0 + 0x3C] = [0x400483FC] = r1 = [[0x1FFF03F4] + 0x00] = [0x0C000110] = 0x202000FB   ; SYSCON中未明確暫存器。

0x1FFF029C 4956      LDR      r1,[pc,#344] ; @0x1FFF03F8        ;

0x1FFF029E 6809      LDR      r1,[r1,#0x00] ;

0x1FFF02A0 6001 STR      r1,[r0,#0x00]

; [r0 + 0x00] = [0x400483C0] = r1 = [[0x1FFF03F8] + 0x00] = [0x0C000124] = 0x0000001F   ; SYSCON中未明確暫存器。

0x1FFF02A2 4956      LDR      r1,[pc,#344] ; @0x1FFF03FC        ;

0x1FFF02A4 6809      LDR      r1,[r1,#0x00] ;

0x1FFF02A6 6041 STR      r1,[r0,#0x04] ;

; [r0 + 0x04] = [0x400483C4] = r1 = [[0x1FFF03FC] + 0x00] = [0x0C000128] = 0x00000007   ; SYSCON中未明確暫存器。

0x1FFF02A8 4955      LDR      r1,[pc,#340] ; @0x1FFF0400        ;

0x1FFF02AA 6809      LDR      r1,[r1,#0x00] ;

0x1FFF02AC 6081 STR      r1,[r0,#0x08] ;

; [r0 + 0x08] = [0x400483C8] = r1 = [[0x1FFF0400] + 0x00] = [0x0C00012C] = 0x000000FB   ; SYSCON中未明確暫存器。

0x1FFF02AE 4855      LDR      r0,[pc,#340] ; @0x1FFF0404        ;

0x1FFF02B0 493B      LDR      r1,[pc,#236] ; @0x1FFF03A0        ;

0x1FFF02B2 6800      LDR      r0,[r0,#0x00] ;

0x1FFF02B4 3140      ADDS     r1,r1,#0x40 ;

0x1FFF02B6 6008 STR      r0,[r1,#0x00] ;

; [r1 + 0x00] = [[0x1FFF03A0] + 0x40 + 0x00] = [0x40048080] = r0 = [[0x1FFF0404] + 0x00] = [0x0C00011C] = 0x000000DF   ; SYSCON中未明確暫存器。

0x1FFF02B8 4853      LDR      r0,[pc,#332] ; @0x1FFF0408        ;

0x1FFF02BA 4C39      LDR      r4,[pc,#228] ; @0x1FFF03A0        ;

0x1FFF02BC 6800      LDR      r0,[r0,#0x00] ;

0x1FFF02BE 3C40      SUBS     r4,r4,#0x40 ;

0x1FFF02C0 62A0 STR      r0,[r4,#0x28] ;

; [r4 + 0x28] = [[0x1FFF03A0] - 0x40 + 0x28] = [0x40048018] = r0 = [[0x1FFF0408] + 0x00] = [0x0C000120] = 0x000000DA   ; SYSCON中未明確暫存器。

最後進行判斷,跳轉到0x1FFF02D0。

0x1FFF02C2 78D0      LDRB     r0,[r2,#0x03] ;r0 = [r2 + 0x03].B = [0x0C00013F].B = 0

0x1FFF02C4 285A      CMP      r0,#0x5A

0x1FFF02C6 D103      BNE      0x1FFF02D0 ;如果r0不等於0x5A則跳轉到0x1FFF02D0,否則接下來的執行

0x1FFF02C8 2001      MOVS     r0,#0x01

0x1FFF02CA 0300      LSLS     r0,r0,#12

0x1FFF02CC F7FFFEBC  BL.W     0x1FFF0048 ;如果r0 = 0x5A,則r0 = 0x1 << 12;並跳轉到0x1FFF0048

0x1FFF02D0 484E      LDR      r0,[pc,#312] ; @0x1FFF040C

0x1FFF02D2 F000FEE5  BL.W     0x1FFF10A0 ;r0 = [0x1FFF040C] = 0x40040000;並跳轉到0x1FFF10A0

接下來從ROM地址0x1FFF130C處讀取值0x00020005並寫入0x40040000處(Flash控制器地址空間,未明確該暫存器定義)。以及對0x40040000暫存器的第19bit設定為1。推測可能是設定Flash的某些引數。

0x1FFF10A0 499A      LDR      r1,[pc,#616] ; @0x1FFF130C

0x1FFF10A2 6001 STR      r1,[r0,#0x00] ; [r0 + 0x00] = [0x40040000] = r1 = [0x1FFF130C] = 0x00020005

0x1FFF10A4 6801      LDR      r1,[r0,#0x00]

0x1FFF10A6 2201 MOVS     r2,#0x01

0x1FFF10A8 04D2      LSLS     r2,r2,#19

0x1FFF10AA 4311      ORRS     r1,r1,r2

0x1FFF10AC 6001 STR      r1,[r0,#0x00] ; [r0] = [0x40040000] = r1 = [r0] | (0x1 << 19) = 0x000A0005

0x1FFF10AE 4770 BX       lr

最後返回。然後使r0 = [[0x1FFF0410]] = [0x0C000138] = 0x00000040。

0x1FFF02D6 484E      LDR      r0,[pc,#312] ; @0x1FFF0410

0x1FFF02D8 6800      LDR      r0,[r0,#0x00] ; 返回值r0 = [[0x1FFF0410]] = [0x0C000138] = 0x00000040

0x1FFF02DA F001FEB5  BL.W     0x1FFF2048

並跳轉到0x1FFF2048。

0x1FFF2048 4948      LDR      r1,[pc,#288] ; @0x1FFF216C

0x1FFF204A B280      UXTH     r0,r0

0x1FFF204C 4308      ORRS     r0,r0,r1

; r0 = r0 | r1 = r0 | [0x1FFF216C] = 0x00000040| 0xC0DE0000 = 0xC0DE0040

0x1FFF204E 4948      LDR      r1,[pc,#288] ; @0x1FFF2170

0x1FFF2050 6248 STR      r0,[r1,#0x24]

;[r1 + 0x24]  = [[0x1FFF2170] + 0x24] = [0x40048224] = r0 = 0xC0DE0040

0x1FFF2052 4770 BX       lr

返回讀取0xA0000000C即P0_12即ISP引腳的狀態,如果不是低電平0x00則跳轉到0x1FFF030E也就是使用者程式碼,否則執行接下來的程式碼即進入ISP引導模式。

0x1FFF02DE 6B20      LDR      r0,[r4,#0x30] ;r0 = [0x40048000 + 0x30] = 0x00000013

0x1FFF02E0 0740      LSLS     r0,r0,#29 ; r0 = r0 << 29 = 0x60000000

0x1FFF02E2 D414      BMI      0x1FFF030E

0x1FFF02E4 484B      LDR      r0,[pc,#300] ; @0x1FFF0414

0x1FFF02E6 2105 MOVS     r1,#0x05 ;

0x1FFF02E8 6800      LDR      r0,[r0,#0x00] ; r0 = [[0x1FFF0414]] = [0x0C000144] = 0x0000000C

0x1FFF02EA 0749      LSLS     r1,r1,#29 ; r1 = 5 << 29 = 0xA0000000

0x1FFF02EC 1840      ADDS     r0,r0,r1 ; r0 = r0 + r1 = 0xA000000C

0x1FFF02EE 7800      LDRB     r0,[r0,#0x00] ; r0 = [r0 + 0x00] = [0xA000000C] = 0x00000001

0x1FFF02F0 2800 CMP      r0,#0x00

0x1FFF02F2 D10C      BNE      0x1FFF030E

0x1FFF02F4 4848      LDR      r0,[pc,#288] ; @0x1FFF0418

0x1FFF02F6 4949      LDR      r1,[pc,#292] ; @0x1FFF041C

0x1FFF02F8 6800      LDR      r0,[r0,#0x00]

0x1FFF02FA 6809      LDR      r1,[r1,#0x00]

0x1FFF02FC 6800      LDR      r0,[r0,#0x00]

0x1FFF02FE 4288 CMP      r0,r1

0x1FFF0300 D005      BEQ      0x1FFF030E

0x1FFF0302 4947      LDR      r1,[pc,#284] ; @0x1FFF0420

0x1FFF0304 4288 CMP      r0,r1

0x1FFF0306 D002      BEQ      0x1FFF030E

0x1FFF0308 F7FFFF7A  BL.W     0x1FFF0200

0x1FFF030C BD10      POP      {r4,pc}

0x1FFF030E F7FFFFA5  BL.W     0x1FFF025C

返回的0x1FFF025C程式碼很簡單,恢復之前的r4和lr後返回0x1FFF022E。

0x1FFF025C B510      PUSH     {r4,lr}

0x1FFF025E F7FFFFE6  BL.W     0x1FFF022E

之後的程式碼是將0x40048000的暫存器設定為0x2即SYSCON.SYSMEMREMAP = 0x02即使用者Flash對映到0x0地址處。

0x1FFF022E B570      PUSH     {r4-r6,lr}

0x1FFF0230 4C5B      LDR      r4,[pc,#364] ; @0x1FFF03A0

0x1FFF0232 2000 MOVS     r0,#0x00

0x1FFF0234 2102 MOVS     r1,#0x02

0x1FFF0236 3C40      SUBS     r4,r4,#0x40

0x1FFF0238 6021 STR      r1,[r4,#0x00]

; [r4 + 0x00] = [[0x1FFF03A0] - 0x40] = [0x40048040 - 0x40] = [0x40048000] = r1 = 0x02

然後讀取0-0x1F共8個4位元組計算校驗和,等於0說明使用者程式碼有效,則跳轉到使用者程式碼。

0x1FFF023A 4603 MOV      r3,r0

0x1FFF023C 4602 MOV      r2,r0

0x1FFF023E 4601 MOV      r1,r0

0x1FFF0240 008D      LSLS     r5,r1,#2

0x1FFF0242 595D      LDR      r5,[r3,r5]

0x1FFF0244 1C49      ADDS     r1,r1,#1

0x1FFF0246 18AA      ADDS     r2,r5,r2

0x1FFF0248 2908 CMP      r1,#0x08 ;r1從0累加到7,r5獲取0x00--0x1F的4位元組資料並累加到r2

0x1FFF024A DBF9      BLT      0x1FFF0240

0x1FFF024C 2A00 CMP      r2,#0x00 ;比較r2等於0說明使用者程式碼有效,跳轉

0x1FFF024E D002      BEQ      0x1FFF0256

0x1FFF024C 2A00 CMP      r2,#0x00

0x1FFF024E D002      BEQ      0x1FFF0256

0x1FFF0250 2000 MOVS     r0,#0x00

0x1FFF0252 6020 STR      r0,[r4,#0x00]

0x1FFF0254 BD70      POP      {r4-r6,pc}

0x1FFF0256 F7FFFEF7  BL.W     0x1FFF0048

最後則是設定sp = __initial_sp堆疊,跳轉到使用者程式碼0x4地址處代表的Reset_Handler。

0x1FFF0048 6801      LDR      r1,[r0,#0x00]

0x1FFF004A 468D MOV sp,r1 ;sp = [0x00] = __initial_sp

0x1FFF004C 6841      LDR      r1,[r0,#0x04] ;r1 = [0x04] = Reset_Handler

0x1FFF004E 4708 BX       r1

從此進入使用者程式碼lpc824_startup.s。

版本號

釋出時間

內容

A0

2017--04-16

初次編寫

A1

2017-05-24

增加Bootloader反彙編分析。