作者:chenzhufly(空灵) 发表于2008/03/17 email:chenzhufly@126.com 要做毕业设计了,写论文前,还是分析分析代码吧,这样更加清楚一些,这些代码将在我设计的AT91RM9200板子上做实验,呵呵,开始了哦。。。。。 ..\u-boot-1.3.1\cpu\arm920t\start.S 这个文件的任务是设置处理器状态、初始化中断和内存时序等,并确定是否需要对整个U-Boot代码重定位,最终从Flash中跳转到定位好的内存位置执行 #include #include #include /* ************************************************************************* * * Jump vector table as in table 3.1 in [1] * ************************************************************************* */ //异常处理向量表 .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 expressions:定义一个字,并为之分配空间, 4bytes. .balignl 16,0xdeadbeef /*********************************************************************** .balign[wl] abs-expr, abs-expr, abs-expr 增加位置计数器(在当前子段)使它指向规定的存储边界。第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,单位为字节。例如, ‘.balign 8’向后移动位置计数器直至计数器的值等于8的倍数。如果位置计数器已经是8的倍数,则无需移动。第2个表达式参数(结果必须是纯粹的 数字)给出填充字节的值,用这个值填充位置计数器越过的地方。第2个参数(和逗点)可以省略。如果省略它,填充字节的值通常是0。但在某些系统上,如果本 段标识为包含代码,而填充值被省略,则使用no-op指令填充空白区。第3个参数的结果也必须是纯粹的数字,这个参数是可选的。如果存在第3个参数,它代 表本对齐命令允许跳过字节数的最大值。如果完成这个对齐需要跳过的字节数比规定的最大值还多,则根本无法完成对齐。您可以在边界基准参数后简单地使用两个 逗号,以省略填充值参数(第二参数);如果您在想在适当的时候,对齐操作自动使用no-op指令填充,本方法将非常奏效。 .balignw和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。.balignl使用4字节来填充。例 如,.balignw 4,0x368d将地址对齐到4的倍数,如果它跳过2个字节,GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理 器的存储方式而定)。 如果它跳过1或3个字节,则填充值不明确。 ******************************************************************************/ /* ************************************************************************* * * Startup Code (called from the ARM reset exception vector) * * do important init only if we don't start from memory! * relocate armboot to ram * setup stack * jump to second stage * ************************************************************************* */ //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 /* * These are defined in the board-specific linker script. */ // 声明_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 /* 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 start code */ start_code: /* * set the cpu to SVC32 mode */ // MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd // 使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样可以最好地完成对CRSP或者SPSR的修改 // MSR {} CPSR_|SPSR_,Rm 或者是 MSR {} CPSR_f|SPSR_f,# // MRS与MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分 // bic r0,r1,r2 ;r0:=r1 and not r2 // orr ro,r1,r2 ;r0:=r1 or r2 // 这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI) screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL Mouse wheel to zoom in/out';}" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://file:///C:/DOCUME~1/hf08298/LOCALS~1/Temp/moz-screenshot.jpg');}" onmousewheel="return imgzoom(this);" alt="" /> 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) /* * relocate exception table */ //把异常向量表从_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)//这地方不考虑。。。。。。。。 /* turn off the watchdog */ # if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ # endif ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0] #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */ /* * we do sys-critical inits only at reboot, * not when booting from ram! */ //这个可以看看在..\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: /* relocate U-Boot to RAM */ adr r0, _start /* r0 //把_start的相对地址移到r0 //代码的当前位置 ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ //_TEXT_BASE地址,就是UBOOT在RAM中运行地址 //测试判断是从Flash启动,还是RAM,如果相同,就已经在RAM运行,否则就是FLASH中运行 //其中TEXT_BASE在..\u-boot-1.3.1\board\at91rm9200dk\config.mk cmp r0, r1 /* don't reloc during debug */ beq stack_setup //如果在FLASH中运行,要把FLASH中的BOOT代码移到RAM中,然后再运行 ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 //r2保存UBOOT代码大小 add r2, r0, r2 /* r2 //r2保存UBOOT代码最后地址 copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ //从源地址[r0]读取8个字节到寄存器,每读一个就更新一 次r0地址 stmia r1!, {r3-r10} /* copy to target address [r1] */ //拷贝寄存器r3-r10的值保存到 [r1]指明的地址,每写一 个字节,就增加1 cmp r0, r2 /* until source end addreee [r2] */ //判断是否拷贝到[r2]地址,就是引导代码结束位置 ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ #endif /* Set up the stack */ //建立堆栈 stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* leave 3 words for abort-stack */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l: str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l ldr pc, _start_armboot //跳到C代码 _start_armboot: .word start_armboot /* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: /* * flush v4 I/D caches */ // 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 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ //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 /* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */ 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 /* CONFIG_SKIP_LOWLEVEL_INIT */ /* ************************************************************************* * * Interrupt handling * ************************************************************************* */ @ @ 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 /* * 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 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 8) @ 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 stmdb 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 8) @ 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 /* * exception handlers */ .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 /* someone ought to write a more effiction fiq_save_user_regs */ 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/list.asp?boardid=8&t=2756460&tp=U-boot-13.0-rc3 start.S 分析 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 |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )
GMT+8, 2024-9-30 13:28 , Processed in 0.322316 second(s), 12 queries , Gzip On, MemCache On.
Powered by Discuz! X3.5
© 2001-2023 Discuz! Team.