ARM Assembler - Loop getting stuck - c

I'm currently writing some basic ARM assembler. The idea is to control a theoretical furnace and it's cooling/heating system on the LPC2378 development board with an application board attached.
I'm getting there as far as recognising input from the devices is concerned. However, i'm having trouble getting my loop right and I was hoping you guys may be able to point out why my loop is getting stuck, and even after button 1 has been pressed, the fan is not turning on. I previously had the fan working, but when I started trying to control the fan by the temperature of the heater it does not seem to ever start up, and the heater stays on, getting hotter and hotter without the fan to cool it down.
I'm guessing it could come down to the way i'm reading the temperature from the ADC controller.
Please don't hesitate to ask if you need any more information to answer the question.
;=========================================================================
; MotorControl_1
;
; BUT1 turns motor ON and BUT2 turns motor OFF
;
; No interrupt support (except for Reset) - as simple as it gets!
;
; WDH, November 2008
;==========================================================================
; Set-up interrupt vectors and stack support
$ LPC2378InterruptVectors.s
; After a reset exception, execution starts here - the processor is in ARM
; mode and supervisor state with interrupts disabled
SECTION .text:CODE:NOROOT(2)
REQUIRE __vector ; Forces reference to this symbol - required by linker
ARM
; __iar_program_start - defined start symbol.
__iar_program_start:
; Include lpc2378 IO register definitions
#include "iolpc2378.h"
; Include Olimex LPC-2378-STK IO definitions
#include "OlimexLPC2378BoardDefs.h"
; Main entry point - required by debugger
;=========================================================================
; main starts here
;=========================================================================
main
;=========================================================================
; Stack setup
;
; Stack pointer (r13 or SP) is assigned the highest address in a 32kB
; section of on-chip SRAM - assumes a FULL descending stack convention
;=========================================================================
ldr r13, = 0x40008000
ldr r2, = 0x000050 ;Load the delay value
ldr r3, = 0x028 ;Start set point at 40
ldr r4, = 0x000 ;Start temp difference as 0
; ldr r6, = 0x0f ;Temp High Value (15)
; ldr r7, = -0xF ;Set r7 to -15.
; Initialise IO
BL InitialiseARM_IO
BL InitialiseApplicationsBoard_IO
; Initialise the devices and display
BL FanOff
BL errorLedOff
BL systemLedOff
BL heaterOff
LoopStart
BL WaitBUT1
BL heaterOn
BL systemLedOn
BL readTemp
BL checkTemp
CMP r0, #5
BGT errorVal
SUBS r7, r6, r4 ;Performs r7 = r6 - r4 and sets condition register
BLT LoopStart ;Branches to label_bar if r7 < 0 (in which case r6 < r4)
BGT heaterOff
BGT errorLedOn
BGT FanOn
BGT LoopStart
BL WaitBUT2
BL FanOff
BL errorLedOff
BL systemLedOff
BL heaterOff
B LoopStart
;=========================================================================
; InitialiseARM_IO
;
; Initialise the ARM interface, as follows:
;
; Port0(13..14} GPIO Output to on-board LEDs
; bit 13: USB_LINK LED
; bit 14: USB_CONNECT LED
; Port0{18,29} GPIO Input from BUT1 and BUT2
; bit 18: BUT2 pressbutton input
; bit 29: BUT1 pressbutton input
; Port1{18,19} GPIO Inputs from joystick UP and DOWN
; bit 18: UP joystick inout
; bit 19: DOWN joystick input
;=========================================================================
InitialiseARM_IO
; Define data direction for LEDs - the LEDs are connected
; to P0.13 and P0.14
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
;LEDs on ARM board:
; Assign GPIO on P0.13 and P0.14
LDR R5, =PINSEL0 ; Address of PINSEL0
LDR R0, [R5] ; Read current PINSEL0
BIC R0, R0, #0x3C000000 ; Clear bits 26..29
STR R0, [R5] ; Put back in PINSEL0
; Configure output for P0.13 and P0.14
LDR R5, =IO0DIR ; Address of IO0DIR
LDR R0, [R5] ; Read current IO0DIR
ORR R0, R0, #0x6000 ; Set bits 13 and 14 - for P0.13 and P0.14
STR R0, [R5] ; Put back in IO0DIR
; Switches and Joystick inputs on ARM board
; Assign GPIO on P0.18 and P0.29
LDR R5, =PINSEL1 ; Address of PINSEL1
LDR R0, [R5] ; Read current PINSEL1
BIC R0, R0, #0x30 ; Clear bits 4..5
BIC R0, R0, #0x0c000000 ; Clear bits 26..27
STR R0, [R5] ; Put back in PINSEL0
; Configure input for P0.18 and P0.29
LDR R5, =IO0DIR ; Address of IO0DIR
LDR R0, [R5] ; Read current IO0DIR
BIC R0, R0, #0x20000000 ; Clear bits 18 and 29 - for P0.18 and P0.29
BIC R0, R0, #0x00040000
STR R0, [R5] ; Put back in IO0DIR
; Assign GPIO on P1.18 and P1.19
LDR R5, =PINSEL3 ; Address of PINSEL3
LDR R0, [R5] ; Read current PINSEL3
BIC R0, R0, #0xF0 ; Clear bits 4..7
STR R0, [R5] ; Put back in PINSEL3
; Configure input for P1.18 and P1.19
LDR R5, =IO1DIR ; Address of IO1DIR
LDR R0, [R5] ; Read current IO1DIR
BIC R0, R0, #0xc0000 ; Clear bits 18 and 19 - for P1.18 and P1.19
STR R0, [R5] ; Put back in IO1DIR
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; InitialiseApplicationsBoard_IO
;
; Initialise the interface to the Applications Board, as follows:
;
; Port4{0..7} GPIO Output to LEDs, Motor and Heater
; bits 0..4: Temperature error LED indicators
; bit 5: Heater control
; bits 6..7: Motor control
; Port4(8..15} GPIO Input from ADC
; bits 8..15: Inputs from Application Board ADC
;
;=========================================================================
InitialiseApplicationsBoard_IO
; Define data direction for LEDs - the LEDs are connected
; to P0.13 and P0.14
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
; Applications Board Interface via Port4
; Set FIO4MASK to allow access to all bits
LDR R5, =FIO4MASK ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
MOV R0, #0x0 ; Clear all bits of FIO4MASK
STR R0, [R5] ; Put back in IO4DIR
; Configure output for P4.0 to P4.7
LDR R5, =FIO4DIR ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
ORR R0, R0, #0xFF ; Set bits 0..7 - for P4.0 and P4.7
STR R0, [R5] ; Put back in IO4DIR
; Configure input for P4.8 to P4.15
LDR R5, =FIO4DIR ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
BIC R0, R0, #0xFF00 ; Clear bits 8..15 - for P4.8 and P4.15
STR R0, [R5] ; Put back in IO4DIR
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Wait for BUT1 to be pressed
;=========================================================================
WaitBUT1
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
WaitForBUT1Pressed
ldr r0, = IO0PIN ; Address of FIO0PIN register
ldr r1, [r0] ; Read FIO0PIN in to r1
ands r1, r1, # B1_MASK ; Mask out BUT1
beq BUT1Pressed ; Exit LED toggle loop if button is pressed
B WaitForBUT1Pressed
BUT1Pressed
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Wait for BUT2 to be pressed
;=========================================================================
WaitBUT2
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
WaitForBUT2Pressed
ldr r0, = IO0PIN ; Address of FIO0PIN register
ldr r1, [r0] ; Read FIO0PIN in to r1
ands r1, r1, # B2_MASK ; Mask out BUT1
beq BUT2Pressed ; Exit LED toggle loop if button is pressed
B WaitForBUT2Pressed
BUT2Pressed
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Turn Fan Motor ON
;=========================================================================
FanOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x80
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Turn Fan Motor OFF
;=========================================================================
FanOff
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
BIC r0, r0, #0xc0
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Turn On Error LED
;==============================================================================
errorLedOn
STMFD r13!,{r0, r5,r14}
mov r0, # USB_LINK_LED_MASK
ldr r5, = IO0CLR
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Off Error LED
;==============================================================================
errorLedOff
STMFD r13!,{r0, r5,r14}
mov r0, # USB_LINK_LED_MASK
ldr r5, = IO0SET
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn On System LED
;==============================================================================
systemLedOn
STMFD r13!,{r0, r5,r14}
mov r0, # USB_CONNECT_LED_MASK
ldr r5, = IO0CLR
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Off System LED
;==============================================================================
systemLedOff
STMFD r13!,{r0, r5,r14}
mov r0, # USB_CONNECT_LED_MASK
ldr r5, = IO0SET
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Heater On
;==============================================================================
heaterOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x20
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Turn The Heater Off
;==============================================================================
heaterOff
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
AND r0, r0, #0xDF
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Read Temperature
;==============================================================================
readTemp
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR r0, =FIO4PIN
LDR r1, [r0]
LSR r1, r1, #8
AND r1, r1, #0xFF ; r1 now holds the temperature value
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Implement Counter And Read Temperature
;==============================================================================
checkTemp
STMFD r13!,{r0, r14} ; Push PC, r0, Lr
LSR r1, r1, #8
LDR r0, [r2] ; Load delay value in r0.
SUB r0, r0, #0x01 ; Minus 1 from delay.
BEQ readTemp ; Branch if timer counted down.
errorVal
STMFD r13!,{r0, r14} ; Push PC, r0, Lr
SUB r1, r3, r6 ; Subtract set point from temperature, into r6
mov pc, r14 ; Put link register back into PC
END

It looks like you've confused BGT (branch if greater-than) with BLGT (branch and link if greater-than). In the middle of your main loop you have this:
BLT LoopStart ;Branches to label_bar if r7 < 0 (in which case r6 < r4)
BGT heaterOff
BGT errorLedOn
BGT FanOn
BGT LoopStart
If the condition is "greater-than", your code will branch to heaterOff and then when that function returns, it will exit the code entirely. The functions errorLedOn and FanOn can never execute.

Related

ARM64 Backtrace from link register

I am currently trying to get backtrace based on stack pointer and link register on ARM64 device using C program.
Below is example of objdump
bar() calls foo() with 240444: ebfffd68 bl 23f9ec <foo##Base>
I can get link register (lr) and from that getting 23f9ec, save it to backtrace list as last routine.
My question: From below assembly code with current lr 0023f9ec <foo##Base>:, how to calculate to get previous routine with lr is 0023fe14 <bar##Base> using C language?
here is my implementation, but getting wrong previous lr
int bt(void** backtrace, int max_size) {
unsigned long* sp = __get_SP();
unsigned long* ra = __get_LR();
int* funcbase = (int*)(int)&bt;
int spofft = (short)((*funcbase));
sp = (char*)sp-spofft;
unsigned long* wra = (unsigned long*)ra;
int spofft;
int depth = 0;
while(ra) {
wra = ra;
while((*wra >> 16) != 0xe92d) {
wra--;
}
if(wra == 0)
return 0;
spofft = (short)(*wra & 0xffff);
if(depth < max_size)
backtrace[depth] = ra;
else
break;
ra =(unsigned long *)((unsigned long)ra + spofft);
sp =(unsigned long *)((unsigned long)sp + spofft);
depth++;
}
return 1;
}
0023f9ec <foo##Base>:
23f9ec: e92d42f3 push {r0, r1, r4, r5, r6, r7, r9, lr}
23f9f0: e1a09001 mov r9, r1
23f9f4: e1a07000 mov r7, r0
23f9f8: ebfffff9 bl 23f9e4 <__get_SP##Base>
23f9fc: e59f4060 ldr r4, [pc, #96] ; 23fa64 <foo##Base+0x78>
23fa00: e08f4004 add r4, pc, r4
23fa04: e1a05000 mov r5, r0
23fa08: ebfffff3 bl 23f9dc <__get_LR##Base>
23fa0c: e59f3054 ldr r3, [pc, #84] ; 23fa68 <foo##Base+0x7c>
23fa10: e3002256 movw r2, #598 ; 0x256
23fa14: e59f1050 ldr r1, [pc, #80] ; 23fa6c <foo##Base+0x80>
23fa18: e7943003 ldr r3, [r4, r3]
23fa1c: e08f1001 add r1, pc, r1
23fa20: e5934000 ldr r4, [r3]
23fa24: e1a03005 mov r3, r5
23fa28: e6bf4074 sxth r4, r4
23fa2c: e58d4004 str r4, [sp, #4]
23fa30: e1a06000 mov r6, r0
23fa34: e58d0000 str r0, [sp]
23fa38: e59f0030 ldr r0, [pc, #48] ; 23fa70 <foo##Base+0x84>
23fa3c: e08f0000 add r0, pc, r0
23fa40: ebfd456d bl 190ffc <printf#plt>
23fa44: e1a03009 mov r3, r9
23fa48: e1a02007 mov r2, r7
23fa4c: e1a01006 mov r1, r6
23fa50: e0640005 rsb r0, r4, r5
23fa54: ebffff70 bl 23f81c <get_prev_sp_ra2##Base>
23fa58: e3a00000 mov r0, #0
23fa5c: e28dd008 add sp, sp, #8
23fa60: e8bd82f0 pop {r4, r5, r6, r7, r9, pc}
23fa64: 003d5be0 eorseq r5, sp, r0, ror #23
23fa68: 000026c8 andeq r2, r0, r8, asr #13
23fa6c: 002b7ba6 eoreq r7, fp, r6, lsr #23
23fa70: 002b73e5 eoreq r7, fp, r5, ror #7
0023fe14 <bar##Base>:
23fe14: e92d4ef0 push {r4, r5, r6, r7, r9, sl, fp, lr}
23fe18: e24dde16 sub sp, sp, #352 ; 0x160
23fe1c: e59f76a8 ldr r7, [pc, #1704] ; 2404cc <bar##Base+0x6b8>
23fe20: e1a04000 mov r4, r0
23fe24: e59f66a4 ldr r6, [pc, #1700] ; 2404d0 <bar##Base+0x6bc>
23fe28: e1a03000 mov r3, r0
23fe2c: e59f26a0 ldr r2, [pc, #1696] ; 2404d4 <bar##Base+0x6c0>
23fe30: e08f7007 add r7, pc, r7
23fe34: e08f6006 add r6, pc, r6
23fe38: e3a00000 mov r0, #0
23fe3c: e08f2002 add r2, pc, r2
23fe40: e1a05001 mov r5, r1
23fe44: e3a01003 mov r1, #3
23fe48: e59f9688 ldr r9, [pc, #1672] ; 2404d8 <bar##Base+0x6c4>
.....................................................................
24043c: e3a0100f mov r1, #15
240440: e1a0000a mov r0, sl
240444: ebfffd68 bl 23f9ec <foo##Base>
240448: e59f2108 ldr r2, [pc, #264] ; 240558 <bar##Base+0x744>
24044c: e3a01003 mov r1, #3
240450: e08f2002 add r2, pc, r2
240454: e1a05000 mov r5, r0
240458: e1a03000 mov r3, r0
24045c: e3a00000 mov r0, #0
I don't think there's an easy way to do this.
Normally the register ABI of any operating system contains a "frame pointer" register. For example, on Apple's armv7 ABI, this is r7:
0x10006fc0 b0b5 push {r4, r5, r7, lr}
0x10006fc2 02af add r7, sp, 8
0x10006fc4 0448 ldr r0, [0x10006fd8]
0x10006fc6 d0e90c45 ldrd r4, r5, [r0, 0x30]
0x10006fca 0020 movs r0, 0
0x10006fcc fff7a6ff bl 0x10006f1c
0x10006fd0 0019 adds r0, r0, r4
0x10006fd2 6941 adcs r1, r5
0x10006fd4 b0bd pop {r4, r5, r7, pc}
If you dereference r7 there, you get to a pair of pointers, the second of which is lr, and the first of which is the r7 of the calling function, allowing you to repeat this process until you reach the bottom of the stack.
Judging by the assembly you posted, the codebase you're looking at doesn't have that. This means that the only way to obtain the return address is the same way that the code itself does: step forward through each instruction and parse/interpret them until you reach something that loads into pc. This is of course imperfect, since there may be functions in your call stack that do not ever return, but there's not much you can do about that.
It may be tempting to search backwards instead, and while you can do a heuristic approach and probably reach quite reasonable results with it, that is even less reliable than searching forward, since you have absolutely no way of telling whether you arrived at address X by stepping forward from the previous instruction or by explicitly jumping there from somewhere else.

The arm board has no reaction to .bin file

everyone, I am a beginner of embedded system programming, my first led test program for my board, which is mini2440, was written in assembly language as .S file:
.text
.global _start
_start:
bl disable_watch_dog
ldr r0, =0x56000010
mov r1, #0x15400
str r1, [r0]
ldr r0, =0x56000018
mov r1, #0x0
str r1, [r0]
ldr r0, =0x56000014
MAIN_LOOP:
mov r1, #0x0
str r1, [r0]
mov r2, #0x50000
bl delay
mov r1, #0x1e0
str r1, [r0]
mov r2, #0x50000
bl delay
b MAIN_LOOP
disable_watch_dog:
ldr r0, =0x53000000
mov r1, #0x0
str r1, [r0]
mov pc, r14
delay:
sub r2, r2, #0x1
cmp r2, #0x0
bne delay
mov pc, lr
After the compiling I got .bin file from this program and I wrote it to the band flash of mini2440 with opened:
telnet localhost 4444
halt
init_2440
nand erase 0 0x0 0x100000
nand write 0 /home/led/led.bin 0
reset
I did not see any error or warning from the terminal but the board just has no reaction, all the leds were dark. I appreciate it if anyone could explain me about this.
Thanks

Why the interrupt service routine ,PUSH {r3,r4,r5,lr} but POP {r0,r4,r5,lr},which lead to ERROR?

I am using IAR to compile routines, but run error on ARM A7; then i got the question below when i open the .lst file generated by IAR.
It is a ISR, first push {r3, r4, r5, lr}, but POP {r0, r4, r5, lr} when return, the R0 value is changed to the value of R3 before push. So R0 is wrong when returned from irqHandler which lead to error in follow routines.
why ?
void irqHandler(void)
{
878: e92d4038 push {r3, r4, r5, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
87c: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
880: e302000c movw r0, #8204 ; 0x200c
884: e7900004 ldr r0, [r0, r4]
888: e1b00b00 lsls r0, r0, #22
88c: e1b00b20 lsrs r0, r0, #22
890: e1b05000 movs r5, r0
if(id_spin<32)
894: e3550020 cmp r5, #32
898: 2a000000 bcs 8a0 <irqHandler+0x28>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
89c: eafffffe b 89c <irqHandler+0x24>
}
else
{
(pFuncIrq[id_spin-32])();
8a0: e59f0010 ldr r0, [pc, #16] ; 8b8 <.text_8>
8a4: e1b01105 lsls r1, r5, #2
8a8: e0910000 adds r0, r1, r0
8ac: e5100080 ldr r0, [r0, #-128] ; 0x80
8b0: e12fff30 blx r0
}
}
8b4: e8bd8031 pop {r0, r4, r5, pc}
The abi requires a 64 bit aligned stack, so the push of r3 simply facilitates that. Could have chosen any register not already specified. Likewise on the pop they need to clean up the stack the function is prototyped as void so the return (r0) is a dont care and r0-r3 are not expected to be preserved so no reason to match the r3 on each end nor match an r0 on each end.
had they chose a register numbered above r3 (r6 for example) on the push then that would have needed to be matched on the pop. Otherwise the pop would have to be one of r0-r3 to not trash a non-volatile register. (couldnt push r3 then pop r6 that would trash r6)
It does not matter as R0-R3, R12, LR, PC, xPSR are saved on the stack automaticly when the hardware invokes the interrupt vector routine. When bx, ldm, pop, or ldr with PC is invoked hardware executes interrupt routine exit poping those registers.
Do not check your compiler. It knows what it does. Check tour wrong logic - especially printing strings in the interrupt handler.
assemble code with the keyword __irq __arm is below:
__irq __arm void irqHandler(void)
{
878: e24ee004 sub lr, lr, #4
87c: e92d503f push {r0, r1, r2, r3, r4, r5, ip, lr}
volatile u32 *pt = (u32 *)AM_INTC_BASE;
880: e3a044b0 mov r4, #176, 8 ; 0xb0000000
u32 id_spin;
id_spin = *(pt+0x200c/4) & 0x3ff;
884: e302000c movw r0, #8204 ; 0x200c
888: e7900004 ldr r0, [r0, r4]
88c: e1b00b00 lsls r0, r0, #22
890: e1b00b20 lsrs r0, r0, #22
894: e1b05000 movs r5, r0
if(id_spin<32)
898: e3550020 cmp r5, #32
89c: 2a000000 bcs 8a4 <irqHandler+0x2c>
{
#ifdef WHOLECHIPSIM
print("id_spid<32 error...\r\n",0);
#endif
while(1);
8a0: eafffffe b 8a0 <irqHandler+0x28>
}
else
{
(pFuncIrq[id_spin-32])();
8a4: e59f0010 ldr r0, [pc, #16] ; 8bc <.text_8>
8a8: e1b01105 lsls r1, r5, #2
8ac: e0910000 adds r0, r1, r0
8b0: e5100080 ldr r0, [r0, #-128] ; 0x80
8b4: e12fff30 blx r0
}
}
8b8: e8fd903f ldm sp!, {r0, r1, r2, r3, r4, r5, ip, pc}^
Cortex A7 PUSH log ,it just push 7 register, so 32bit aligned is ok
follow link is the log info:
http://img.blog.csdn.net/20170819120758443?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmFpbmJvd2JpcmRzX2Flcw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

Need Help understanding ARM function

I'm still learning ARM and I couldn't understand what this function is supposed to do.
Can you guys help me out explaining how it works?
.text:0006379C EXPORT _nativeD2AB
.text:0006379C _nativeD2AB
.text:0006379C var_28 = -0x28
.text:0006379C
.text:0006379C STMFD SP!, {R4-R11,LR}
.text:000637A0 SUB SP, SP, #0x3A4
.text:000637A4 STMFA SP, {R0-R3}
.text:000637A8 LDR R0, =(_GLOBAL_OFFSET_ - 0x637B8)
.text:000637AC LDR R1, =(__stack_chk - 0x134EAC)
.text:000637B0 ADD R0, PC, R0 ; _GLOBAL_OFFSET_
.text:000637B4 LDR R0, [R1,R0] ; __stack_chk
.text:000637B8 LDR R0, [R0]
.text:000637BC STR R0, [SP,#0x3C8+var_28]
.text:000637C0 MOV R0, #1
.text:000637C4 ADR R1, sub_637D0
.text:000637C8 MUL R0, R1, R0
.text:000637CC MOV PC, R0
.text:000637CC ; End of function _nativeD2AB
.
.got:00134EAC _GLOBAL_OFFSET_TABLE_ DCD 0
.
.got:00134B0C AREA .got, DATA
.got:00134B0C __stack_chk DCD __stack_chkA
.
Found the rest of the function. If I understood some of it correctly, it seems to be scrambling the data, though that may be just a wild guess:
.text:000637D0 sub_637D0
.text:000637D0 MOV R0, #1
.text:000637D4 ADR R1, sub_637E0
.text:000637D8 MUL R0, R1, R0
.text:000637DC MOV PC, R0
.text:000637DC ; End of function sub_637D0
.text:000637E0 sub_637E0
.text:000637E0
.text:000637E0 arg_14 = 0x14
.text:000637E0
.text:000637E0 STR R2, [SP,#arg_14]
.text:000637E4 MOV R0, #1
.text:000637E8 ADR R1, loc_637F4
.text:000637EC MUL R0, R1, R0
.text:000637F0 MOV PC, R0
.text:000637F0 ; End of function sub_637E0
.text:000637F4 loc_637F4
.text:000637F4 STR R2, [SP,#0x28]
.text:000637F8 STR R0, [SP,#0x18]
.text:000637FC MOV R1, #2
.text:00063800 STR R2, [SP,#0x1C]
.text:00063804 STR R0, [SP,#0x20]
.text:00063808 STR R0, [SP,#0x24]
The function has several parts:
Store registers to the stacj and reserve space (Strangely, not restored)
Load to R0 the address of GLOBAL_OFFSET (Once added with PC), to actually access __stack_chk (When added to GLOBAL_OFFSET). This is done in a very strange way.
Load the data at __stack_chk and store it in the stack
Load to R0 the value of sub_637D0, by doing a multiplication by 1. This is the value returned by the function.
So in my opinion, this does not seem to do anything useful...

Why does my SWI instruction hang? (BeagleBone Black, ARM Cortex-A8 cpu)

I'm starting to write a toy OS for the BeagleBone Black, which uses an ARM Cortex-A8-based TI Sitara AM3359 SoC and the U-Boot bootloader. I've got a simple standalone hello world app writing to UART0 that I can load through U-Boot so far, and now I'm trying to move on to interrupt handlers, but I can't get SWI to do anything but hang the device.
According to the AM335x TRM (starting on page 4099, if you're interested), the interrupt vector table is mapped in ROM at 0x20000. The ROM SWI handler branches to RAM at 0x4030ce08, which branches to the address stored at 0x4030ce28. (Initially, this is a unique dead loop at 0x20084.)
My code sets up all the ARM processor modes' SP to their own areas at the top of RAM, and enables interrupts in the CPSR, then executes an SWI instruction, which always hangs. (Perhaps jumping to some dead-loop instruction?) I've looked at a bunch of samples, and read whatever documentation I could find, and I don't see what I'm missing.
Currently my only interaction with the board is over serial connection on UART0 with my linux box. U-Boot initializes UART0, and allows loading of the binary over the serial connection.
Here's the relevant assembly:
.arm
.section ".text.boot"
.equ usr_mode, 0x10
.equ fiq_mode, 0x11
.equ irq_mode, 0x12
.equ svc_mode, 0x13
.equ abt_mode, 0x17
.equ und_mode, 0x1b
.equ sys_mode, 0x1f
.equ swi_vector, 0x4030ce28
.equ rom_swi_b_addr, 0x20008
.equ rom_swi_addr, 0x20028
.equ ram_swi_b_addr, 0x4030CE08
.equ ram_swi_addr, 0x4030CE28
.macro setup_mode mode, stackpointer
mrs r0, cpsr
mov r1, r0
and r1, r1, #0x1f
bic r0, r0, #0x1f
orr r0, r0, #\mode
msr cpsr_csfx, r0
ldr sp, =\stackpointer
bic r0, r0, #0x1f
orr r0, r0, r1
msr cpsr_csfx, r0
.endm
.macro disable_interrupts
mrs r0, cpsr
orr r0, r0, #0x80
msr cpsr_c, r0
.endm
.macro enable_interrupts
mrs r0, cpsr
bic r0, r0, #0x80
msr cpsr_c, r0
.endm
.global _start
_start:
// Initial SP
ldr r3, =_C_STACK_TOP
mov sp, r3
// Set up all the modes' stacks
setup_mode fiq_mode, _FIQ_STACK_TOP
setup_mode irq_mode, _IRQ_STACK_TOP
setup_mode svc_mode, _SVC_STACK_TOP
setup_mode abt_mode, _ABT_STACK_TOP
setup_mode und_mode, _UND_STACK_TOP
setup_mode sys_mode, _C_STACK_TOP
// Clear out BSS
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
b _clear_bss_check$
_clear_bss$:
stmia r0!, {r5-r8}
_clear_bss_check$:
cmp r0, r1
blo _clear_bss$
// Load our SWI handler's address into
// the vector table
ldr r0, =_swi_handler
ldr r1, =swi_vector
str r0, [r1]
// Debug-print out these SWI addresses
ldr r0, =rom_swi_b_addr
bl print_mem
ldr r0, =rom_swi_addr
bl print_mem
ldr r0, =ram_swi_b_addr
bl print_mem
ldr r0, =ram_swi_addr
bl print_mem
enable_interrupts
swi_call$:
swi #0xCC
bl kernel_main
b _reset
.global _swi_handler
_swi_handler:
// Get the SWI parameter into r0
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
// Save lr onto the stack
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}
Those debugging prints produce the expected values:
00020008: e59ff018
00020028: 4030ce08
4030ce08: e59ff018
4030ce28: 80200164
(According to objdump, 0x80200164 is indeed _swi_handler. 0xe59ff018 is the instruction "ldr pc, [pc, #0x20]".)
What am I missing? It seems like this should work.
The firmware on the board changes the ARM execution mode and the locations of
the vector tables associated with the various modes. In my own case (a bare-metal
snippet code executed at Privilege Level 1 and launched by BBB's uBoot) the active vector table is at address 0x9f74b000.
In general, you might use something like the following function to locate the
active vector table:
static inline unsigned int *get_vectors_address(void)
{
unsigned int v;
/* read SCTLR */
__asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0\n"
: "=r" (v) : : );
if (v & (1<<13))
return (unsigned int *) 0xffff0000;
/* read VBAR */
__asm__ __volatile__("mrc p15, 0, %0, c12, c0, 0\n"
: "=r" (v) : : );
return (unsigned int *) v;
}
change
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}
to
stmfd sp!, {r0-r3, r12, lr}
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
bl print_uint32
ldmfd sp!, {r0-r3, r12, pc}^
PS: You don't restore SPSR into CPSR of interrupted task AND you also scratch registers which are not banked by the cpu mode switch.

Resources