0K6410学习之初学Uboot_stage1

来源:互联网 发布:音频编辑软件 手机版 编辑:程序博客网 时间:2024/06/08 06:59

今天喝的水真多,如我所言,已经有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_SPLldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irqldrpc, _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  5undefined_instruction:get_bad_stackbad_save_user_regsbl do_undefined_instruction.align5software_interrupt:get_bad_stackbad_save_user_regsbl do_software_interrupt.align5prefetch_abort:get_bad_stackbad_save_user_regsbl do_prefetch_abort.align5data_abort:get_bad_stackbad_save_user_regsbl do_data_abort.align5not_used:get_bad_stackbad_save_user_regsbl do_not_used#ifdef CONFIG_USE_IRQ.align5irq:get_irq_stackirq_save_user_regsbl do_irqirq_restore_user_regs.align5fiq:get_fiq_stack/* someone ought to write a more effiction fiq_save_user_regs */irq_save_user_regsbl do_fiqirq_restore_user_regs#else.align5irq:get_bad_stackbad_save_user_regsbl do_irq.align5fiq:get_bad_stackbad_save_user_regsbl 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 */mrsr0, cpsrbicr0, r0, #0x3forrr0, r0, #0xd3msrcpsr, 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 */movr0, #0mcrp15, 0, r0, c7, c7, 0/* flush v3/v4 cache */mcrp15, 0, r0, c8, c7, 0/* flush v4 TLB *//* * disable MMU stuff and caches */mrcp15, 0, r0, c1, c0, 0bicr0, r0, #0x00002300@ clear bits 13, 9:8 (--V- --RS)bicr0, r0, #0x00000087@ clear bits 7, 2:0 (B--- -CAM)orrr0, r0, #0x00000002@ set bit 2 (A) Alignorrr0, r0, #0x00001000@ set bit 12 (I) I-Cache/* Prepare to disable the MMU */#if 0adrr1, mmu_disable_phys/* We presume we're within the first 1024 bytes */andr1, r1, #0x3fcldrr2, _TEXT_PHY_BASEldrr3, =0xfff00000andr2, r2, r3orrr2, r2, r1bmmu_disable.align 5/* Run in a single cache-line */mmu_disable:mcrp15, 0, r0, c1, c0, 0nopnopmovpc, r2#endif#endif

1、调用lowlevel_init底层初始化函数。初始化PLL,初始化mux,memory关闭看门狗。(应该对照芯片手册仔细分析的)。

 

2、复制完代码后,就使能MMU

#ifdef CONFIG_ENABLE_MMUenable_mmu:/* enable domain access */ldrr5, =0x0000ffffmcrp15, 0, r5, c3, c0, 0/* load domain access register *//* Set the TTB register */ldrr0, _mmu_table_baseldrr1, =CONFIG_SYS_PHY_UBOOT_BASEldrr2, =0xfff00000bicr0, r0, r2orrr1, r0, r1mcrp15, 0, r1, c2, c0, 0/* Enable the MMU */mrcp15, 0, r0, c1, c0, 0orrr0, r0, #1/* Set CR_M to enable MMU *//* Prepare to enable the MMU */adrr1, skip_hw_initandr1, r1, #0x3fcldrr2, _TEXT_BASEldrr3, =0xfff00000andr2, r2, r3orrr2, r2, r1bmmu_enable.align 5/* Run in a single cache-line */mmu_enable:mcrp15, 0, r0, c1, c0, 0nopnopmovpc, r2#endif

1、清除堆,设置栈,为什么?调用C函数。

skip_hw_init:/* Set up the stack*/stack_setup:ldrr0, =CONFIG_SYS_UBOOT_BASE/* base of copy in DRAM*/subr0, r0, #CONFIG_SYS_MALLOC_LEN/* malloc area*/subr0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo*/subsp, r0, #12/* leave 3 words for abort-stack*/clear_bss:ldrr0, _bss_start/* find start of bss segment*/ldrr1, _bss_end/* stop here*/mov r2, #0/* clear*/clbss_l:strr2, [r0]/* clear loop... */addr0, r0, #4cmpr0, r1bleclbss_l

1、CPU初始化完毕之后,能看到这么一段代码。

#ifndef CONFIG_NAND_SPLldrpc, _start_armboot_start_armboot:.word start_armboot#elsebnand_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。。。。