今天喝的水真多,如我所言,已经有3天没有看空间了,表现不错。确实,空间里面似乎没有什么值得我关注的了,呵呵。恩,刚刚粗略的将u-boot-2010.03的里面arm11的源代码看了一下,我用的是ARM11的板子,里面有一些是参考了arm9的分析资料,分析完后还是觉得有必要总结一下的,以防自己忘记,好的,说正题,stag1。
声明:里面有些东西可能是我误解了,仅供参考,欢迎大家一起交流。
一、 打开cpu/arm1176/start.S,这个文件是系统上电后执行的第一个代码,但是不是编译器执行的第一个代码,原因相信都明白。从START.S开始看,头文件,这个没什么好说的了,接着往下就是:
.globl _start _start: b reset
.globl定义一个全局变量,可以被其他文档引用。这个是整个uboot程序的入口,可在链接脚本board/s3c2410/u-boot.lds中找到,链接脚本中定义了这个程序的入口地址,这条指令的意思就是板子一上来就复位啦~~~
二、 该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~0x0000 0020,刚好8条指令
#ifndef CONFIG_NAND_SPL 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 _pad: .word 0x12345678 /* now 16*4=64 */ #else . = _start + 64 #endif .global _end_vect _end_vect: .balignl 16,0xdeadbeef
其中.word伪 *** 作用于分配一段字内存单元(分配的单元都是字对齐的),并用异常进行初始化。.long和.int原理一样。.balign伪 *** 作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign详细用法百度一下。
如果系统出现中断异常就会执行下列代码,代码还是位于start.s中
/* * 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、TEXT_BASE在研发板相关的目录中的config.mk文档中定义, 他定义了代码在运行时所在的地址, 同时_TEXT_BASE中保存了这个地址。
_TEXT_BASE: .word TEXT_BASE
2、下面代码声明_armboot_start并用_start 来进行初始化,在board/u-boot.lds中定义。
.globl _armboot_start _armboot_start: .word _start
3、
1、以下代码声明_bss_start并用__bss_start来初始化,其中__bss_start定义在和板相关的u-boot.lds中,_bss_start中
1、_bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时
地址的影响.
.globl _bss_start _bss_start: .globl _bss_start _bss_start: .word __bss_start
3、_bss_end也是同样的道理.
.word __bss_start . globl _bss_end _ bss_end: .word _end
1、OK,看复位函数,不,应该叫复位代码吧!
/* * the actual reset code */ reset: /* * set the cpu to SVC32 mode */ mrs r0, cpsr bic r0, r0, #0x3f orr r0, r0, #0xd3 msr cpsr, r0
/* 首先将cpu设置为我们熟悉的管理模式(通过设置cpsr的低5位为10011实现)。同时禁止IRQ、FIQ。即cpsr的第七第六位设置为11,这个在我之前的中断那一博文上面就有说明的。
1、关闭Cache和MMU,为什么?据说:如果只按复位键,而不关掉板子重新上电,就会造成cache中可能残留之前对cache *** 作的数据。我们称之为“脏数据”,它会映像我们的调试结果,造成假象。(有机会试试)
当然,在这里无效cache和MMU肯定还有别的原因。比如在初始化阶段,
可以认为我们只有一个任务在跑,没有必要,也不允许使用地址变换。因此最好应该无效掉MMU。(参考ARM79的说法)
#ifndef CONFIG_NAND_SPL /* * 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 /* Prepare to disable the MMU */ #if 0 adr r1, mmu_disable_phys /* We presume we're within the first 1024 bytes */ and r1, r1, #0x3fc ldr r2, _TEXT_PHY_BASE ldr r3, =0xfff00000 and r2, r2, r3 orr r2, r2, r1 b mmu_disable .align 5 /* Run in a single cache-line */ mmu_disable: mcr p15, 0, r0, c1, c0, 0 nop nop mov pc, r2 #endif #endif
1、调用lowlevel_init底层初始化函数。初始化PLL,初始化mux,memory关闭看门狗。(应该对照芯片手册仔细分析的)。
2、复制完代码后,就使能MMU
#ifdef CONFIG_ENABLE_MMU enable_mmu: /* enable domain access */ ldr r5, =0x0000ffff mcr p15, 0, r5, c3, c0, 0 /* load domain access register */ /* Set the TTB register */ ldr r0, _mmu_table_base ldr r1, =CONFIG_SYS_PHY_UBOOT_BASE ldr r2, =0xfff00000 bic r0, r0, r2 orr r1, r0, r1 mcr p15, 0, r1, c2, c0, 0 /* Enable the MMU */ mrc p15, 0, r0, c1, c0, 0 orr r0, r0, #1 /* Set CR_M to enable MMU */ /* Prepare to enable the MMU */ adr r1, skip_hw_init and r1, r1, #0x3fc ldr r2, _TEXT_BASE ldr r3, =0xfff00000 and r2, r2, r3 orr r2, r2, r1 b mmu_enable .align 5 /* Run in a single cache-line */ mmu_enable: mcr p15, 0, r0, c1, c0, 0 nop nop mov pc, r2 #endif
1、清除堆,设置栈,为什么?调用C函数。
skip_hw_init: /* Set up the stack*/ stack_setup: ldr r0, =CONFIG_SYS_UBOOT_BASE /* base of copy in DRAM */ sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area*/ sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo*/ 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, #0 /* clear*/ clbss_l: str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l
1、CPU初始化完毕之后,能看到这么一段代码。
#ifndef CONFIG_NAND_SPL ldr pc, _start_armboot _start_armboot: .word start_armboot #else b nand_boot /* .word nand_boot*/ #endif #ifdef CONFIG_ENABLE_MMU _mmu_table_base: .word mmu_table #endif #ifndef CONFIG_NAND_SPL
显然,我们这里并没有复制代码,所以直接进入到C函数,_start_armboot。
调用第一个C函数啦,开始进入c的世界,uboot启动stage 2!
跳转到start_armboot函数入口,_start_armboot字保存函数入口指针
start_armboot函数在lib_arm/board.c中实现
总结完stage1,就差不多要睡觉了。待续stage2。。。。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)