1 ROM-bootloader disassembly analysis
In Keil (IAR cannot implement this yet, and other IDEs have not been tried. This section focuses on code analysis, and there is no need to consider the tool software too much). Cancel the "Run to main" option on the Debug tab of Option, and select Stop after reset in Setting. This way, after entering the debugging interface, the program stops at the beginning of the bootloader, and the assembly code flow of the bootloader in the ROM can be analyzed.
Figure 35 ROM-Bootloader debugging settings for LPC824
The ROM is located between 0x1FFF0000 and 0x1FFF3000, with a total of 12KB of ROM, including the bootloader, ROM-API, etc.
Figure 35 LPC824 ROM and RAM location map
Enter the debugging interface or press the RST button during debugging, it will stay at the first code of booloader. At the same time, modify the addresses 0x0 and 0x1FFF0000 in the Memory window, and the content remains unchanged. It can be seen that the ROM at the position of 0x1FFF0000 after reset is also mapped to the address 0x0 (after comparison, it is temporarily speculated that only the first 512Bytes of content are mapped to the addresses 0x0-0x1FF, and the content from 0x200 is still the user's Flash code).
Note that the byte order of ARM is little-endian, and the last bit of PC must be 1 (indicating thumb mode). According to the startup logic of ARM, SP and PC are initialized to the two 32-bit (4-byte) contents at addresses 0x0 and 0x04, which are 0x10000FFC and 0x1FFF0008, respectively, because the logic of ARM is that the contents at addresses 0x08 and 0x0C are the addresses of the two interrupt service mileages, NMI and HardFault.
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
It can be seen that at this time SP=0x10000FFC is the top of SRAM0, and PC=0x1FFF0008 is the first instruction address.
Figure 35 LPC824 ROM-Bootloader startup debugging interface
From the above figure, we can see that NMI is not used, because the NMI interrupt of LPC824 uses the NMISRC register in the SYSCON module to select a peripheral interrupt as the source of the ARM Cortex-M0+ core NMI interrupt, which is not used in the bootloader. Therefore, NMI_Handler is not needed and directly jumps to the content of @0x1FFF000C, that is, the address 0x1FFF0011.
0x1FFF0008 4A00 LDR r2,[pc,#0] ; @0x1FFF000C
0x1FFF000A 4710 BX r2
The content at 0x1FFF000C is exactly the execution address of HardFault_Handler, and the content is also 0x1FFF0011. Therefore, the actual code execution result is at 0x1FFF0011. Therefore, HardFault_Handler also executes the code at 0x1FFF0011. (In fact, it should be ROM to ensure that the code is flawless and HardFault_Handler is not used).
The next step is to read the contents at 0x1FFF0064 and 0x1FFF0068 and store them in the r2 and r3 registers. The content of r3 is 0x1FFF0078, which is an address in the ROM. The content stored in this address is 0x000002FC, which is the address of the user code CRP. By reading the content of this address, the CRP value of the user code can be read and the CRP1/2/3 level can be verified.
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]
Obviously, to compare CRP with CRP1/2/3, first read the CRP value of the current user code and the value of constant CRP1/3. Then compare the CRP value with CRP3 and CRP1. If one of them is the same, jump to 0x1FFF0028, otherwise jump to 0x1FFF002C. The effect after the above execution is as follows:
Figure 35 LPC824 ROM-Bootloader CRP1/3 comparison and conditional execution
The consequence of the comparison success or failure is whether the code of 0x1FFF0028 is executed. If they are the same, the code is executed. The value of the address saved at 0x1FFF006C (the address is 0x1FFF007C) (the value is 0x87654321) is loaded into r4. Otherwise, r4 remains as it is, that is, the CRP value of the user code, and then r4 is saved to the location where the r2 register value is used as the address. The content of r2 is 0x400483F0, which is the register address space of SYSCON, before the DEVICE_ID register. However, the function of this address register is not explained in the data sheet. According to the bootloader flowchart, it is speculated that it is to enable debugging.
Figure 35 LPC824 ROM-Bootloader saves CRP value to 0x400483F0
The following code is:
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
By reading the contents of 0x1FFF0054 and 0x1FFF0058 as addresses (0x0C00013C and 0x1FFF008C respectively), the contents of these two addresses are read into r4 and r5, and then r4 and r5 are compared. If they are the same, 0x1FFF003E is skipped and jumps directly to 0x1FFF0042. Therefore, the meaning of this code is to decide whether to execute the two lines of code 0x1FFF003E by comparing the values at 0x0C00013C (Reserved area) and 0x1FFF008C (constant in ROM). The result of this routine is that the values of the two addresses are 0x0000C0FA, so the code is skipped.
The difference between executing this line of code and not is whether the content of r2 is the value of the address at 0x1FFF0050 (the address is 0x0C000118) or the value of the address at 0x1FFF005C (the address is 0x1FFF0088). After modifying the Z flag of PSR to change the result of CMP instruction, we can see that the value of r2 changes to 0x100003FF or 0x10001FFF, and then save r2 to the sp register, which shows that its function is to modify the stack address executed by ROM-Bootloader. It is speculated that the value at the address 0x0C00013C may be some information about the ROM version or chip die version?
Finally, jump to the content saved in 0x1FFF0060 as the new PC execution address (the new PC execution address is 0x1FFF0269, note that the last bit of PC must be 1 to indicate thumb mode).
0x1FFF0044 4A06 LDR r2,[pc,#24] ; @0x1FFF0060
0x1FFF0046 4710 BX r2
After jumping to 0x1FFF0268, the code is as follows:
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
Save r4 and lr to the stack, then read the content at 0x1FFF03D8 as the value of the address (the address is 0x0C00013C, the Reserved area), save it to r0, and compare it with the content at 0x1FFF03DC (the constant in ROM) saved to r1. If they are not equal, it will stay on the following statement forever.
0x1FFF0274 E7FE B 0x1FFF0274
After this routine test, the contents of r0 and r1 are both 0x0000C0FA, which is the same as the previous judgment. Is it suspected that another version comparison is being performed? The execution effect is as follows:
Figure 35 ROM-Bootloader comparison version information of LPC824?
Next is multiple reads and writes, reading from the address space near 0x0C000100, and writing to the address space approximately 0x40048000--0x400483FFSYSCON address space. The 0x0C000100 area is Reserved, and it is speculated that TRIM data is modulated, etc., which will be analyzed in detail later, 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, register not specified in 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 Register not specified in 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 ; Undefined register in SYSCON.
0x1FFF028C 2100 MOVS r1,#0x00 ; r1 = 0
0x1FFF028E 6101 STR r1,[r0,#0x10] ; [r0 + 0x10] = [0x400483D0] = 0 Register not defined in SYSCON.
; [r0 + 0x3C] = [0x400483D0] = r1 = 0 ; Undefined register in 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 ; Undefined register in 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 ; Undefined register in 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 ; Undefined register in 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 ; Undefined register in 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 ; Undefined register in 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 ; Undefined register in SYSCON.
Finally, make a judgment and jump to 0x1FFF02D0.
0x1FFF02C2 78D0 LDRB r0,[r2,#0x03] ;r0 = [r2 + 0x03].B = [0x0C00013F].B = 0
0x1FFF02C4 285A CMP r0,#0x5A
0x1FFF02C6 D103 BNE 0x1FFF02D0 ;If r0 is not equal to 0x5A, jump to 0x1FFF02D0, otherwise the next execution
0x1FFF02C8 2001 MOVS r0,#0x01
0x1FFF02CA 0300 LSLS r0,r0,#12
0x1FFF02CC F7FFFEBC BL.W 0x1FFF0048 ; if r0 = 0x5A, then r0 = 0x1 << 12; and jump to 0x1FFF0048
0x1FFF02D0 484E LDR r0,[pc,#312] ; @0x1FFF040C
0x1FFF02D2 F000FEE5 BL.W 0x1FFF10A0 ;r0 = [0x1FFF040C] = 0x40040000; and jump to 0x1FFF10A0
Next, the value 0x00020005 is read from the ROM address 0x1FFF130C and written to 0x40040000 (the Flash controller address space, the register definition is not clear). And the 19th bit of the 0x40040000 register is set to 1. It is speculated that it may be setting some parameters of the 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
Finally, return. Then make r0 = [[0x1FFF0410]] = [0x0C000138] = 0x00000040.
0x1FFF02D6 484E LDR r0,[pc,#312] ; @0x1FFF0410
0x1FFF02D8 6800 LDR r0,[r0,#0x00] ; Return value r0 = [[0x1FFF0410]] = [0x0C000138] = 0x00000040
0x1FFF02DA F001FEB5 BL.W 0x1FFF2048
And jump to 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
Return to read 0xA0000000C, which is the status of P0_12, the ISP pin. If it is not low level 0x00, jump to 0x1FFF030E, which is the user code. Otherwise, execute the following code to enter the ISP boot mode.
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
The returned code 0x1FFF025C is very simple, and it returns 0x1FFF022E after restoring the previous r4 and lr.
0x1FFF025C B510 PUSH {r4,lr}
0x1FFF025E F7FFFFE6 BL.W 0x1FFF022E
The following code sets the register at 0x40048000 to 0x2, i.e. SYSCON.SYSMEMREMAP = 0x02, which means that the user Flash is mapped to address 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
Then read 8 4-byte checksums from 0 to 0x1F, and if it is equal to 0, it means the user code is valid, then jump to the user code.
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 accumulates from 0 to 7, r5 gets 4 bytes of data from 0x00 to 0x1F and accumulates to r2
0x1FFF024A DBF9 BLT 0x1FFF0240
0x1FFF024C 2A00 CMP r2,#0x00 ; Compare r2 equal to 0, indicating that the user code is valid, jump
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
Finally, the stack is set to sp = __initial_sp and jumps to the Reset_Handler represented by the user code address 0x4.
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
From here enter the user code lpc824_startup.s.
Previous article:LPC824 IAP implementation method
Next article:Summary of problems when downloading programs in ISP mode using FlashMagic tool on LPC54618
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- The US asked TSMC to restrict the export of high-end chips, and the Ministry of Commerce responded
- The US asked TSMC to restrict the export of high-end chips, and the Ministry of Commerce responded
- ASML predicts that its revenue in 2030 will exceed 457 billion yuan! Gross profit margin 56-60%
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- Products + DC brushless motor control + drive kit
- Due to the epidemic, you are under home quarantine. Has your salary been reduced?
- ARM9-compatible soft-core processor design: based on FPGA
- 5G era promotes PCB development in multiple fields
- What is the principle of keyless entry for cars?
- What does OVRD_ALERT in BQ76940 OVRD_ALERT mean?
- Can SDRAM chips be used on 2-layer boards?
- Let Arduino play with your useless STM32 board Part 2
- Recommend a low thermal potential relay
- Modern rectifier technology - active power factor correction technology