免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2643 | 回复: 4
打印 上一主题 下一主题

[BootLoader] 请教为何还木设置堆栈就调用c代码的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-12-07 17:51 来自手机 |只看该作者 |倒序浏览
本帖最后由 ljpdxj 于 2012-12-07 17:54 编辑

start_code的地方,刚刚设置进入superviser模式,就bl去控制led灯了,请问这里还木准备堆栈为什么可以这么用?
Ps,ipad发贴,有些不好编辑。。。如下红色块的地方
..\u-boot-1.3.1\cpu\arm920t\start.S
这个文件的任务是设置处理器状态、初始化中断和内存时序等,并确定是否需要对整个U-Boot代码重定位,最终从Flash中跳转到定位好的内存位置执行
#include
#include
#include

//异常处理向量表
.globl _start
_start: b start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
// .word expression_r_rs:定义一个字,并为之分配空间, 4bytes.
.balignl 16,0xdeadbeef


//TEXT_BASE代表代码在运行时所在的地址
//TEXT_BASE在..\u-boot-1.3.1\board\at91rm9200dk\config.mk
_TEXT_BASE:
.word TEXT_BASE
// 声明 _armboot_start 并用 _start 来进行初始化
// 标号_start在前面有定义
.globl _armboot_start
_armboot_start:
.word _start

// 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在与板相关的u-boot.lds中。
// _bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在
// 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时
// 地址的影响. _bss_end也是同样的道理.
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de

.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif

start_code:

// MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd
// 使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样可以最好地完成对CRSP或者SPSR的修改
// MSR {} CPSR_|SPSR_,Rm 或者是 MSR {} CPSR_f|SPSR_f,#<32-bit immediate>
// MRS与MSR配合使用,作为更新PSR的"读取--修改--写回"序列的一部分
// bic r0,r1,r2 ;r0:=r1 and not r2
// orr ro,r1,r2 ;r0:=r1 or r2
// 这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI)

mrs r0,cpsr
// 取得当前程序状态寄存器cpsr到r0。
bic r0,r0,#0x1f
// 把中断全部清除,只置位模式控制位
orr r0,r0,#0xd3
// 1 1 0 10011
//IRQ FIQ STATE MODE
// 禁止IRQ,FIQ中断,使用ARM指令,工作在supervisor模式
msr cpsr,r0
// 设置cpsr
bl coloured_LED_init
bl red_LED_on

//coloured_LED_init()和red_LED_on()
//在..\u-boot-1.3.1\board\at91rm9200dk\led.c
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)

//把异常向量表从_start开始的16个32位数拷贝到0x00地址
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)//这地方不考虑。。。。。。。。
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]

mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif


ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif

//这个可以看看在..\u-boot-1.3.1\u-boot-1.3.1\include\configs\at91rm9200dk.h中是否定义
//如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,跳到cpu_init_crit
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
#ifdef CONFIG_AT91RM9200
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:
adr r0, _start
//把_start的相对地址移到r0
//代码的当前位置
ldr r1, _TEXT_BASE
//_TEXT_BASE地址,就是UBOOT在RAM中运行地址

//测试判断是从Flash启动,还是RAM,如果相同,就已经在RAM运行,否则就是FLASH中运行
//其中TEXT_BASE在..\u-boot-1.3.1\board\at91rm9200dk\config.mk
cmp r0, r1
beq stack_setup
//如果在FLASH中运行,要把FLASH中的BOOT代码移到RAM中,然后再运行
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2
//r2保存UBOOT代码大小
add r2, r0, r2
//r2保存UBOOT代码最后地址

copy_loop:
ldmia r0!, {r3-r10}
//从源地址[r0]读取8个字节到寄存器,每读一个就更新一次r0地址
stmia r1!, {r3-r10}
//拷贝寄存器r3-r10的值保存到 [r1]指明的地址,每写一个字节,就增加1
cmp r0, r2
//判断是否拷贝到[r2]地址,就是引导代码结束位置
ble copy_loop
#endif
#endif


//建立堆栈
stack_setup:
ldr r0, _TEXT_BASE
sub r0, r0, #CFG_MALLOC_LEN
sub r0, r0, #CFG_GBL_DATA_SIZE
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12
clear_bss:
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0x00000000
clbss_l:
str r2, [r0]
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot //跳到C代码
_start_armboot: .word start_armboot


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:

// MCR 指令的格式为:
//MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。
//MCR 指令用于将ARM 处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2 为协处理器将要执行的操作,源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器
//ARM的存储器管理是通过系统控制协处理器CP15完成的。CP15包含16个32位寄存器C0~C15
//在系统模式下访问CP15中的寄存器需要使用MCR和MRC两条指令。
//在用户模式下访问CP15中的寄存器需要使用软中断(SWI)调用的方式
mov r0, #0
mcr p15, 0, r0, c7, c7, 0
mcr p15, 0, r0, c8, c7, 0

//C1是一个控制寄存器,它控制MMU(MPU)的使能,数据Cache或统一Cache的使能,指令Cache的使能,写缓冲使能等
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0

mov ip, lr
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
//这个地方是不是应该加一句bl lowlevel_init
//初始化sdram等,这样是不是就可以直接从0x0地址直接执行uboot了,需要做个实验。。。。
#else
bl lowlevel_init
#endif
mov lr, ip
mov pc, lr
#endif

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80

.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+ @ set base 2 words into abort stack
ldmia r2, {r2 - r3} @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12//入栈
add r8, sp, #S_PC
sb r8, {sp, lr}^ @ Calling SP, LR
str lr, [r8, #0] @ Save calling PC
mrs r6, spsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr//出栈
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm
.macro get_bad_stack //寄存器R13在ARM指令中常用作堆栈指针
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r13, r13, #(CFG_GBL_DATA_SIZE+ @ reserved a couple spots in abort stack
str lr, [r13] @ save caller lr / spsr
mrs lr, spsr
str lr, [r13, #4]
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13
mov lr, pc
movs pc, lr
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm

.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
#ifdef CONFIG_USE_IRQ
.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs
.align 5
fiq:
get_fiq_stack

irq_save_user_regs
bl do_fiq
irq_restore_user_regs
#else
.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif

参考:
1) U-boot-13.0-rc3 start.S 分析http://bbs.21ic.com/club/bbs/lis ... tart.S+%B7%D6%CE%F6
2) uboot中c语言对汇编语言标号的引用http://blog.chinaunix.net/u/26710/showart_403988.html
3) 如何开发arm(3)
http://dayu.spaces.eepw.com.cn/articles/article/item/15636

论坛徽章:
0
2 [报告]
发表于 2012-12-17 23:19 |只看该作者
只要c code中没有用到栈 自然就不需要栈已经初始化好

一般来说 只要一个c function没有局部变量 没有调用别的function,就不会进行栈操作才对

你可以看看那2个c function的assembly code,看有没有操作sp

论坛徽章:
0
3 [报告]
发表于 2013-02-21 22:16 |只看该作者
内联函数?

论坛徽章:
0
4 [报告]
发表于 2013-02-23 12:47 |只看该作者
回复 2# onlyxuyang

搞不懂,就算不对栈操作,那这段代码不是变成位置相关代码了?
C函数的链接地址应该是在RAM中吧,这时候RAM都还没初始化吧?怎么就跳到RAM里面执行了?

论坛徽章:
0
5 [报告]
发表于 2013-04-17 23:47 |只看该作者
uboot所在的那片memory应该已经初始化了啊(dram or sram or nor flash?)

而且我记得uboot应该是都是位置相关代码,在build的时候制作uboot image的时候是会给uboot指定一个base address的,

runtime的时候会把uboot读到这个base address来执行,那么bl 所要跳转到的function的address就是已知的吧。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP