Skip to content

天楚锐齿

人工智能 云计算 大数据 物联网 IT 通信 嵌入式

天楚锐齿

  • 下载
  • 物联网
  • 云计算
  • 大数据
  • 人工智能
  • Linux&Android
  • 网络
  • 通信
  • 嵌入式
  • 杂七杂八

mini6410板uboot的start.S

2018-03-13
#include <config.h>
#include <version.h>
#ifdef CONFIG_ENABLE_MMU
#include <asm/proc/domain.h>
#endif
#include <regs.h>#ifndef CONFIG_ENABLE_MMU
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE     CFG_UBOOT_BASE  @加入不用MMU,又没有定义CFG_PHY_UBOOT_BASE的话,则CFG_PHY_UBOOT_BASE为CFG_UBOOT_BASE
#endif
#endif

/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/

.globl _start
_start: b     reset                                  @中断向量表入口,复位中断:复位后第一条指令就从这里开始执行,这里跳转到reset标号处执行。
ldr     pc, _undefined_instruction       @未定义指令中断。
ldr     pc, _software_interrupt           @软件中断。
ldr     pc, _prefetch_abort                @预取指令失败中断。
ldr     pc, _data_abort                      @数据访问失败中断。
ldr     pc, _not_used                         @保留中断。
ldr     pc, _irq                                 @IRQ中断。
ldr     pc, _fiq                                 @FIQ中断。

_undefined_instruction:
.word undefined_instruction            @这个WORD数据就是一个个中断处理函数的地址,上面的ldr指令会把这个地址装入pc,然后CPU就会执行各个函数,这个文件的后半段会有这些地址的指令。
_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
_pad:
.word 0x12345678 /* now 16*4=64 */ @填充一个字,从b reset开始,一直到本位置构成总共64字节。
.global _end_vect
_end_vect:

.balignl 16,0xdeadbeef                    @16字节对齐,如果前面不是16字节的整数倍,而且刚好空出4个字节的话,就用0xdeadbeef填充,这里不用填充,因为上面是64字节,刚好是16字节的倍数。
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don’t start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/

_TEXT_BASE:
.word     TEXT_BASE                     @定义一个_TEXT_BASE变量,存放了TEXT_BASE的值。这个TEXT_BASE会在Config.mk里面定义,这里定义成0x57e00000(MMU方式则为0xc7e00000)

/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word     CFG_PHY_UBOOT_BASE   @定义一个_TEXT_PHY_BASE的变量,对应的值是CFG_PHY_UBOOT_BASE,就是地址0x00000044里面存放的值是CFG_PHY_UBOOT_BASE

.globl _armboot_start                         @定义一个_armboot_start的全局变量,对应的值是_start,就是地址0x00000048里面存放的值是_start(0x00000000),只是一个标号,在c语言中可作为指针来引用。比如monitor_flash_len = _bss_start – _armboot_start;这个c语句,实际就是__bss_start的值减去_start的值。

_armboot_start:
.word _start

/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start                        @同上

.globl _bss_end
_bss_end:
.word _end                                 @同上

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word     0x0badc0de                    @同上

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de                        @同上
#endif

/*
* the actual reset code
*/

reset:
/*
* set the cpu to SVC32 mode
*/
mrs     r0,cpsr
bic     r0,r0,#0x1f
orr     r0,r0,#0xd3
msr     cpsr,r0                 @设置CPU为保护模式。

/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov     r0, #0
mcr     p15, 0, r0, c7, c7, 0     /* flush v3/v4 cache */
mcr     p15, 0, r0, c8, c7, 0     /* flush v4 TLB */

/*
* disable MMU stuff and caches
*/
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                                                     @不用MMU,不用cache。

/* Peri port setup */
ldr     r0, =0x70000000
orr     r0, r0, #0x13
mcr     p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff),设置内存为256M。

#ifdef CONFIG_BOOT_ONENAND                                                    @mini6410不用ONENAND。
ldr     r0, =0x70000000          @ onenand controller setup
orr     r0, r0, #0x100000
ldr     r1, =0x4000
orr     r1, r1, #0xe0
str     r1, [r0]

#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)
orr     r0, r0, #300          @ disable watchdog
mov     r1, #1
str     r1, [r0]

mov     r1, #0x23000000          @ start buffer register
orr     r1, r1, #0x30000
orr     r1, r1, #0xc800
#else
mov     r1, =0x20000000          @ start buffer register
orr     r1, r1, #0xc30000
orr     r1, r1, #0xc800
#endif

sub     r0, r1, #0x0400          @ start address1 register

ldr     r2, [r1, #0x84]          @ ecc bypass
orr     r2, r2, #0x100
str     r2, [r1, #0x84]

mov     r3, #0x0          @ DFS, FBA
str     r3, [r0, #0x00]
str     r3, [r0, #0x04]          @ select dataram for DDP as 0

mov     r4, #0x104          @ interrupt register
mov     r5, #0x0002          @ FPA, FSA
mov     r6, #0x0800          @ BSA

onenand_bl1_load:
str     r5, [r0, #0x1c]          @ save FPA, FSA
orr     r6, r6, #0x02          @ BSC
str     r6, [r1, #0x00]          @ save BSA, BSC
str     r3, [r1, r4]          @ clear interrupt
str     r3, [r1, #0x80]          @ write load command

mov     r7, #0x100          @ need small delay

onenand_wait_loop1:
subs     r7, r7, #0x1
bne     onenand_wait_loop1

add     r5, r5, #0x2          @ next FPA, FSA
sub     r6, r6, #0x2
add     r6, r6, #0x200          @ next BSA
cmp     r5, #0x8
bne     onenand_bl1_load
#endif

/*
* Go setup Memory and board specific bits prior to relocation.
*/
bl     lowlevel_init     /* go setup pll,mux,memory */                                    @做底层低级别初始化,参考lowlevel_init.S。

/* when we already run in ram, we don’t need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr     r0, =0xff000fff                                                                             @因为uboot将被拷贝到0x57e00000(或MMU下0xc7e00000)开始的2M空间内,而且大小不超过,。所以如果在内存执行则PC肯定在0x57e0000往上的地址空间,如果在step stone执行的话,PC肯定在0x00200000往下的地址空间。而且两者的偏移相同,所以只比较中间几位就可以了。
bic     r1, pc, r0          /* r0 <- current base addr of code */
ldr     r2, _TEXT_BASE          /* r1 <- original base addr in ram */           @这里载入的是_TEXT_BASE地址对应的TEXT_BASE值,即0x57e00000。
bic     r2, r2, r0          /* r0 <- current base addr of code */
cmp     r1, r2                  /* compare r0, r1                  */
beq     after_copy          /* r0 == r1 then skip flash copy   */                   @已经拷贝到了内存

#ifdef CONFIG_BOOT_NOR               /* relocate U-Boot to RAM */                @mini6410不使用NOR。
adr     r0, _start          /* r0 <- current position of code   */                 @这个adr是相对PC寻址,翻译为sub r0,PC,#xx,就是_start的当前地址,也许就是0x00000000。
ldr     r1, _TEXT_PHY_BASE     /* r1 <- destination                */           @r1里面存的是链接时的起始地址,即0xc7e00000的位置。
ldr     r2, _armboot_start
ldr     r3, _bss_start
sub     r2, r3, r2          /* r2 <- size of armboot            */                   @代码段大小,即_bss段起始位置-.text段的起始位置。
add     r2, r0, r2          /* r2 <- source end address         */                @那么即将要拷贝的就是从_start当前位置开始到_start+代码段大小的位置。

nor_copy_loop:
ldmia     r0!, {r3-r10}          /* copy from source address [r0]    */
stmia     r1!, {r3-r10}          /* copy to   target address [r1]    */          @做拷贝
cmp     r0, r2               /* until source end addreee [r2]    */               @拷贝是否完成
ble     nor_copy_loop
b     after_copy
#endif

#ifdef CONFIG_BOOT_NAND
mov     r0, #0x1000                    @传入参数,从下面copy_from_nand看不出这个参数有什么用?
bl     copy_from_nand                 @从NANDFLASH拷贝到内存。
#endif

#ifdef CONFIG_BOOT_MOVINAND
ldr     sp, _TEXT_PHY_BASE        @设置栈地址为_TEXT_PHY_BASE,即CFG_PHY_UBOOT_BASE(0x57e00000)
bl     movi_bl2_copy                   @调用c函数从SD卡拷贝到内存,参考Movi.c文件
b     after_copy                          @拷贝之后执行的位置
#endif

#ifdef CONFIG_BOOT_ONENAND
ldr     sp, =0x50000000          @ temporary stack

#ifdef CONFIG_S3C6400
mov     r1, =0x20000000          @ start buffer register
orr     r1, r1, #0xc30000
orr     r1, r1, #0xc800
#else
mov     r1, #0x23000000          @ start buffer register
orr     r1, r1, #0x30000
orr     r1, r1, #0xc800
#endif

ldr     r2, [r1, #0x84]          @ ecc bypass
orr     r2, r2, #0x100
str     r2, [r1, #0x84]

sub     r0, r1, #0x0400          @ start address1 register

str     r3, [r0, #0x00]
str     r3, [r0, #0x04]          @ select dataram for DDP as 0

mov     r4, #0x104          @ interrupt register

mov     r6, #0x0c00          @ fixed dataram1 sector number
str     r6, [r1, #0x00]

mov     r3, #0x0          @ DFS, FBA
mov     r5, #0x0000          @ FPA, FSA
ldr     r9, =CFG_PHY_UBOOT_BASE     @ destination

onenand_bl2_load:
str     r3, [r0, #0x00]          @ save DFS, FBA
str     r5, [r0, #0x1c]          @ save FPA, FSA

mov     r7, #0x0          @ clear interrupt
str     r7, [r1, r4]
str     r7, [r1, #0x80]          @ write load command

mov     r8, #0x1000
onenand_wait_loop2:
subs     r8, r8, #0x1
bne     onenand_wait_loop2

onenand_wait_int:               @ wait INT and RI
ldr     r7, [r1, r4]
mov     r8, #0x8000
orr     r8, r8, #0x80
tst     r7, r8
beq     onenand_wait_int

mov     r7, #0x0          @ clear interrupt
str     r7, [r1, r4]

mov     r8, #0xc00          @ source address (dataram1)                  @拷贝固定位置的固定大小数据到内存,内存其实地址为0xc7e00000。

     mov     r10, #0x40          @ copy loop count (64 = 2048 / 32)

stmia     sp, {r0-r7}          @ backup

onenand_copy_to_ram:
ldmia     r8!, {r0-r7}
stmia     r9!, {r0-r7}
subs     r10, r10, #0x1
bne     onenand_copy_to_ram

ldmia     sp, {r0-r7}          @ restore

add     r5, r5, #0x4          @ next FPA
cmp     r5, #0x100          @ last FPA?
bne     onenand_bl2_load

/* next block */
mov     r5, #0x0          @ reset FPA
add     r3, r3, #0x1          @ next FBA
cmp     r3, #0x2          @ last FBA?
bne     onenand_bl2_load
b     after_copy
#endif

#ifdef CONFIG_BOOT_ONENAND_IROM                      @onenand IROM
ldr     sp, _TEXT_PHY_BASE                                 @设置栈指针
bl     onenand_bl2_copy                                       @调用c函数,定义在Onenand_cp.c文件中,实际调用IROM里面的拷贝函数来实现的。
b     after_copy
#endif

after_copy:
ldr     r0, =ELFIN_GPIO_BASE                                  @设置GPP13/GPP14口为1
ldr     r1, =0xC00
str     r1, [r0, #GPPDAT_OFFSET]

#ifdef CONFIG_ENABLE_MMU                                       @设置MMU,参考lowlevel_init.S的mmu_table
enable_mmu:
/* enable domain access */
ldr     r5, =0x0000ffff                                              @设置domain0-domain7为不检查访问控制,domain值在MMU描述符里面定义

     mcr     p15, 0, r5, c3, c0, 0          @ load domain access register

/* Set the TTB register */
ldr     r0, _mmu_table_base
ldr     r1, =CFG_PHY_UBOOT_BASE                         @TTB为一级页表的虚拟基地址,只保存高18位,所以页表需要align到14位宽。
ldr     r2, =0xfff00000                                            @因为mmu_table的高12位将被映射到虚拟地址,所以这里清除高12位,得到低20位地址跟虚拟基本地址的高12位组合,得到在虚拟地址空间里面的页表地址。即0xc7e00000 | mmu_table。
bic     r0, r0, r2
orr     r1, r0, r1
mcr     p15, 0, r1, c2, c0, 0

/* Enable the MMU */
mmu_on:
mrc     p15, 0, r0, c1, c0, 0
orr     r0, r0, #1               /* Set CR_M to enable MMU */ @设置MMU控制寄存器M比特为1,使能MMU。
mcr     p15, 0, r0, c1, c0, 0
nop                                                                      @等待稳定。
nop
nop
nop
#endif

skip_hw_init:
/* Set up the stack                                  */
stack_setup:
#ifdef CONFIG_MEMORY_UPPER_CODE
ldr     sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE – 0xc)                  @设置栈指针为MMU方式:0xc7e00000+2MB-12字节保留,即0xc8000000-12字节位置。栈在_TEXT_BASE上面。
#else
ldr     r0, _TEXT_BASE          /* upper 128 KiB: relocated uboot   */     @r0为0xc7e00000,栈在_TEXT_BASE下面。
sub     r0, r0, #CFG_MALLOC_LEN     /* malloc area                      */   @保留1MB的malloc()用
sub     r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */        @保留128KB全局数据
#ifdef CONFIG_USE_IRQ
sub     r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)     @保留IRQ和FIQ栈
#endif
sub     sp, r0, #12          /* leave 3 words for abort-stack    */              @保留12个字节

#endif

clear_bss:
ldr     r0, _bss_start          /* find start of bss segment        */        @把bss段的值全部清0,_bss_start和_bss_end定义在上面开始位置,而__bss_start和__end定义在lds文件中。
ldr     r1, _bss_end          /* stop here                        */
mov      r2, #0x00000000          /* clear                            */

clbss_l:
str     r2, [r0]          /* clear loop…                    */                       @清零bss段
add     r0, r0, #4
cmp     r0, r1
ble     clbss_l

ldr     pc, _start_armboot                                                            @把start_armboot这个c函数的地址载入pc寄存器,实现到c入口的跳转;注意,前面所有代码都是用的相对地址跳转(如果用到了符号地址,除了拷贝到内存的地方之外,其他都是在做加减法,没有直接使用),所以代码都在0x00000000附件执行,只有在这里用了绝对地址跳转,跳转到了链接所指定的符号表地址即0xc7exxxxx位置区间去执行了。start_armboot定义在Board.c文件中。

_start_armboot:
.word start_armboot

#ifdef CONFIG_ENABLE_MMU
_mmu_table_base:
.word mmu_table
#endif

/*
* copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)
* r0: size to be compared
* Load 1’st 2blocks to RAM because U-boot’s size is larger than 1block(128k) size
*/
.globl copy_from_nand
copy_from_nand:
mov     r10, lr          /* save return address */                         @保存返回地址

mov     r9, r0                                                                         @保存传入的参数到r9
/* get ready to call C functions */
ldr     sp, _TEXT_PHY_BASE     /* setup temp stack pointer */    @调用c函数前做准备,设置栈指针。
sub     sp, sp, #12                                                                   @留出12字节空间作保护
mov     fp, #0               /* no previous frame, so fp=0 */           @设置帧指针为0,参考汇编和c的相互调用。
mov     r9, #0x1000                                                               @传一个立即数给r9,看不出有啥用?只在下面校验的时候用上了。
bl     copy_uboot_to_ram                                                        @调用c函数从NAND拷贝到内存。参考Nand_cp.c文件

3:     tst      r0, #0x0                                                                   @如果c函数调用成功,则r0保存的返回值为0.
bne     copy_failed                                                                  @拷贝失败。

ldr     r0, =0x0c000000                                                           @这里是stepping stone区域,NAND启动时,硬件先从NAND读进来放到这个位置,然后映射到0x00000000位置。
ldr     r1, _TEXT_PHY_BASE                                                    @拷贝到内存的地址,0x57e00000,这里是刚才从NAND拷贝进来放到这里的,所以这两个区域都是代码,应该完全一样。
1:     ldr     r3, [r0], #4                                                                @逐一比较。
ldr     r4, [r1], #4
teq     r3, r4
bne     compare_failed     /* not matched */                      @比较失败
subs     r9, r9, #4                                                            @减4字节继续下一个比较
bne     1b

4:     mov     lr, r10          /* all is OK */                                 @拷贝成功,返回
mov     pc, lr

copy_failed:
nop               /* copy from nand failed */                         @拷贝失败,一直循环
b     copy_failed

compare_failed:
nop               /* compare failed */                                  @比较失败,一直循环
b     compare_failed

/*                                                                                      @下面的函数应该不会进入执行。
* we assume that cache operation is done before. (eg. cleanup_before_linux())
* actually, we don’t need to do anything about cache if not use d-cache in U-Boot
* So, in this function we clean only MMU. by scsuh
*
* void     theLastJump(void *kernel, int arch_num, uint boot_params);
*/
#ifdef CONFIG_ENABLE_MMU
.globl theLastJump
theLastJump:
mov     r9, r0
ldr     r3, =0xfff00000
ldr     r4, _TEXT_PHY_BASE
adr     r5, phy_last_jump
bic     r5, r5, r3
orr     r5, r5, r4
mov     pc, r5
phy_last_jump:
/*
* disable MMU stuff
*/
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

mcr     p15, 0, r0, c8, c7, 0     /* flush v4 TLB */

mov     r0, #0
mov     pc, r9
#endif
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE     72   @所有寄存器加起来72字节。下面是调用c函数前的栈结构,最后用r0作为指针传这个栈的内存地址到c函数。

#define S_OLD_R0     68
#define S_PSR          64  @r16为CPSR
#define S_PC          60    @r15为PC,指令指针。
#define S_LR          56    @r14为lr,保存c函数返回地址。
#define S_SP          52    @r13为栈指针。#define S_IP          48     @r12为IP,c函数内部暂存寄存器。
#define S_FP          44    @r11为FP,c里面的帧指针,每个函数进入时默认必须0。
#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

/*
* use bad_save_user_regs for abort/prefetch/undef/swi …
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/

.macro     bad_save_user_regs          @保存寄存器值,用在abort/prefetch/undef/swi等中断里面。
sub     sp, sp, #S_FRAME_SIZE          @ carve out a frame on current user stack,堆栈指针sp(参考下面get_bad_stack里面的保护模式堆栈)往下挪72字节

     stmia     sp, {r0 – r12}               @ Save user registers (now in svc mode) r0-r12,从sp往上依次保存r0~r12

ldr     r2, _armboot_start
sub     r2, r2, #(CFG_MALLOC_LEN)
sub     r2, r2, #(CFG_GBL_DATA_SIZE+8)     @ set base 2 words into abort stack
ldmia     r2, {r2 – r3}               @ get values for “aborted” pc and cpsr (into parm regs),参考下面get_bad_stack里面的保护模式堆栈知道,这里存放了中断前的pc和cpsr值,所以这里r2=pc, r3=cpsr
add     r0, sp, #S_FRAME_SIZE          @ grab pointer to old stack,这里r0就是减72字节之前的栈位置。

add     r5, sp, #S_SP                        @r5为sp加52字节,就是刚才存放r0~r12的上面。

     mov     r1, lr                                     @r1保存lr
stmia     r5, {r0 – r3}               @ save sp_SVC, lr_SVC, pc, cpsr,这里保存的就是老的保护模式栈位置,保护模式lr,中断前的pc,中断前的cpsr
mov     r0, sp                    @ save current stack into r0 (param register),r0存放栈指针(作为c函数的参数指针传入c函数使用)。现在栈的内容从sp往上依次是中断前r0~r12, 中断后的sp_svr, 中断后的lr_svr, 中断前pc, 中断前cpsr。

     .endm

.macro     irq_save_user_regs            @保存IRQ/FIQ中断的寄存器。
sub     sp, sp, #S_FRAME_SIZE                                     @栈指针减掉72字节,用来保存寄存器值
stmia     sp, {r0 – r12}               @ Calling r0-r12          @保存r0~r12,stmia是先压入第一个寄存器,再地址加,然后再压入第二个寄存器,地址再加。
add     r8, sp, #S_PC               @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.  @r8指向栈指针往上60字节处
stmdb     r8, {sp, lr}^               @ Calling SP, LR         @保存用户模式的sp,lr,就是中断前的sp,lr,还有,stmdb是先地址减,再压入最后一个寄存器,然后地址再减,再压入倒数第二个寄存器。
str     lr, [r8, #0]               @ Save calling PC              @保存中断前的pc
mrs     r6, spsr
str     r6, [r8, #4]               @ Save CPSR                   @保存spsr,就是中断前的cpsr
str     r0, [r8, #8]               @ Save OLD_R0                @保存r0
mov     r0, sp                                                             @r0设置sp,这时栈从sp往上依次是中断前r0~r12, 中断前的sp, 中断前的lr, 中断前pc, 中断前cpsr,中断前r0

     .endm

.macro     irq_restore_user_regs
ldmia     sp, {r0 – lr}^               @ Calling r0 – lr    @恢复中断前r0~r12, 中断后的sp,中断后的lr

     mov     r0, r0                                                       @相当于nop,延时
ldr     lr, [sp, #S_PC]               @ Get PC               @恢复中断前的pc到lr
add     sp, sp, #S_FRAME_SIZE                            @恢复中断前的sp
subs     pc, lr, #4               @ return & move spsr_svc into cpsr @返回中断的程序,并且恢复spsr到cpsr
.endm.macro get_bad_stack
ldr     r13, _armboot_start          @ setup our mode stack (enter in banked mode)                   @设置到_armboot_start即_start链接地址位置,也就是0xc7e00000。参考上面的栈设置更好理解。这里也就设置了保护模式的栈sp地址。

     sub     r13, r13, #(CFG_MALLOC_LEN)     @ move past malloc pool                                         @保留1MB的malloc()用
sub     r13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for abort stack @保留128KB的全局数据,保留8字节来保存接下来的两个4字节。str     lr, [r13]               @ save caller lr in position 0 of saved stack                   @保存lr,就是中断之前的pc+4或pc+8值。
mrs     lr, spsr               @ get the spsr
str     lr, [r13, #4]               @ save spsr in position 1 of saved stack                  @保存spsr,就是中断之前的cpsr值。这时保护模式sp就是r13的值为_armboot_start – CFG_MALLOC_LEN – (CFG_GBL_DATA_SIZE+8) – 4(存放中断前的pc值) – 4(存放中断前的cpsr值)

mov     r13, #MODE_SVC               @ prepare SVC-Mode
@ msr     spsr_c, r13
msr     spsr, r13               @ switch modes, make sure moves will execute         @先把spsr设置为管理模式
mov     lr, pc                    @ capture return pc                                                 @因为这条指令的PC值是指向它后面的第二条指令(就是movs pc,lr的下一条),所以pc先传到lr,再从lr传到pc时,刚好跳转到movs pc,lr的下一条指令。
movs     pc, lr                    @ jump to next instruction & switch modes.              @因为用的是movs带S的指令,会自动把spsr的值导入cpsr,从而实现到管理模式的切换。
.endm.macro get_bad_stack_swi
sub     r13, r13, #4               @ space on current stack for scratch reg.       @设置栈指针为当前栈,先减4字节,为了保存下面的r0
str     r0, [r13]               @ save R0’s value.                                              @保存r0
ldr     r0, _armboot_start          @ get data regions start                            @从_armboot_start往下保留数据
sub     r0, r0, #(CFG_MALLOC_LEN)     @ move past malloc pool
sub     r0, r0, #(CFG_GBL_DATA_SIZE+8)     @ move past gbl and a couple spots for abort stack @最后的8字节用来保存下面的两个4字节。
str     lr, [r0]               @ save caller lr in position 0 of saved stack            @保存lr,就是中断之前的pc+4或pc+8值。
mrs     r0, spsr               @ get the spsr
str     lr, [r0, #4]               @ save spsr in position 1 of saved stack          @保存spsr,就是中断之前的cpsr值。
ldr     r0, [r13]               @ restore r0                                                    @恢复进入前的r0
add     r13, r13, #4               @ pop stack entry                                      @恢复栈位置。
.endm

.macro get_irq_stack               @ setup IRQ stack
ldr     sp, IRQ_STACK_START                                      @设置栈指针,在上面定义这个变量,实际计算在Cpu.c里面,为_armboot_start – CFG_MALLOC_LEN – CFG_GBL_DATA_SIZE – 4
.endm

.macro get_fiq_stack               @ setup FIQ stack
ldr     sp, FIQ_STACK_START                                      @设置栈指针,在上面定义这个变量,实际计算在Cpu.c里面,为IRQ_STACK_START – CONFIG_STACKSIZE_IRQ
.endm

/*
* exception handlers
*/
.align     5                                     @异常处理32字节对齐
undefined_instruction:                         @未定义指令 异常
get_bad_stack                               @得到栈
bad_save_user_regs                      @保存寄存器值到栈作为传入c处理函数的指针参数所对应的内存位置。
bl     do_undefined_instruction        @跳到c函数执行,定义在Interrupts.c文件中。

.align     5
software_interrupt:
get_bad_stack_swi                      @得到栈
bad_save_user_regs                   @保存寄存器值
bl     do_software_interrupt         @跳到c函数执行,定义在Interrupts.c文件中。

.align     5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl     do_prefetch_abort           @跳到c函数执行,定义在Interrupts.c文件中。

.align     5
data_abort:
get_bad_stack
bad_save_user_regs
bl     do_data_abort              @跳到c函数执行,定义在Interrupts.c文件中。

.align     5
not_used:
get_bad_stack
bad_save_user_regs
bl     do_not_used                @跳到c函数执行,定义在Interrupts.c文件中。

#ifdef CONFIG_USE_IRQ

.align     5
irq:
get_irq_stack
irq_save_user_regs
bl     do_irq                   @跳到c函数执行,定义在Interrupts.c文件中。
irq_restore_user_regs    @恢复寄存器值

.align     5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl     do_fiq                  @跳到c函数执行,定义在Interrupts.c文件中。
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
.align 5
.global arm1136_cache_flush
arm1136_cache_flush:
mcr     p15, 0, r1, c7, c5, 0     @ invalidate I cache
mov     pc, lr               @ back to caller

#if defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_CINTEGRATOR)
/* Use the IntegratorCP function from board/integratorcp/platform.S */
#elif defined(CONFIG_S3C64XX)
/* For future usage of S3C64XX*/
#else
.align     5
.globl reset_cpu
reset_cpu:
ldr     r1, rstctl     /* get addr for global reset reg */
mov     r3, #0x2     /* full reset pll+mpu */
str     r3, [r1]     /* force reset */
mov     r0, r0
_loop_forever:
b     _loop_forever
rstctl:
.word     PM_RSTCTRL_WKUP

#endif

860次阅读

Post navigation

前一篇:

qemu-img使用帮助

后一篇:

mini6410板uboot的cpu_init.S

发表评论 取消回复

邮箱地址不会被公开。 必填项已用*标注

个人介绍

需要么,有事情这里找联系方式:关于天楚锐齿

=== 美女同欣赏,好酒共品尝 ===

微信扫描二维码赞赏该文章:

扫描二维码分享该文章:

分类目录

  • Linux&Android (79)
  • Uncategorized (1)
  • 下载 (28)
  • 云计算 (37)
  • 人工智能 (8)
  • 大数据 (24)
  • 嵌入式 (34)
  • 杂七杂八 (34)
  • 物联网 (59)
  • 网络 (23)
  • 通信 (21)

文章归档

近期文章

  • 使用Python渲染OpenGL的.obj和.mtl文件
  • 用LVGL图形库绘制二维码
  • Android使用Messenger和SharedMemory实现跨app的海量数据传输
  • CAN信号的c语言解析代码
  • QT qml下DBus的使用例子

近期评论

  • 硕发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《Android9下用ethernet 的Tether模式来做路由器功能》

阅读量

  • 使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序 - 16,805次阅读
  • 卸载深信服Ingress、SecurityDesktop客户端 - 12,078次阅读
  • 车机技术之Android Automotive - 6,661次阅读
  • 车机技术之车规级Linux-Automotive Grade Linux(AGL) - 5,861次阅读
  • Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误 - 5,711次阅读
  • 在Android9下用ndk编译vSomeIP和CommonAPI以及使用例子 - 5,658次阅读
  • linux下的unbound DNS服务器设置详解 - 5,601次阅读
  • linux的tee命令导致ssh客户端下的shell卡住不动 - 4,998次阅读
  • 车机技术之360°全景影像(环视)系统 - 4,897次阅读
  • libwebp(处理webp图像)的安装和使用 - 4,749次阅读

功能

  • 文章RSS
  • 评论RSS

联系方式

地址
深圳市科技园

时间
周一至周五:  9:00~12:00,14:00~18:00
周六和周日:10:00~12:00

标签

android AT命令 centos Hadoop hdfs ip ipv6 kickstart linux mapreduce mini6410 modem OAuth openstack os python socket ssh uboot 内核 协议 安装 嵌入式 性能 报表 授权 操作系统 数据 数据库 月报 模型 汽车 测试 深信服 深度学习 源代码 神经网络 统计 编译 网络 脚本 虚拟机 调制解调器 车机 金融
© 2023 天楚锐齿