start_kernel之前的汇编代码分析

Boot中执行下面两句话之后,进入uclinux内核。

theKernel = (void (*)(int, int, unsigned int))((uint32_t)0x08003001);

theKernel(0, 2189, ((uint32_t)0x20000100));

首先来到0x0800 3000处,此时携带有三个参数,R0、R1、R2,分别是0,2189,0x2000 0100.

0x0800 3000对应着下面stext的汇编代码。

代码阅读说明:

① @后面的内容标示是注释语句

② ARM或者THUMB指令的选取,在\include\asm-arm\unified.h中,定义了使用ARM,THUMB为空

③ 偏移量#PROC_INFO_SZ等,在\include\asm\asm-offset.h中宏定义

1.1   head-mommu.S

文件在arch\arm\kernel\head-nommu.S,text.head段,有stext、__after_proc_init两段组成,内核从这里开始启动,然后通过各种调用,最终进入C语言的start_kernel函数,这段代码执行流程如下:

(1)       调用__lookup_processor_type,传入R9(CPU基址寄存器的值),成功后获得当前的proc_info结构体信息,地址放入R10;

(2)       调用__lookup_machine_type,BootLoader传给内核的R1值,成功后获得当前的machine_desc结构体信息,地址放入R8;

(3)       执行__v7m_setup,进行必要的初始化;

(4)       执行__switch_data,并最终跳转到C语言的start_kernel函数。

.section ".text.head", "ax"

ENTRY(stext)

cpsid       i                           @ disable interrupts       //cortex-M3特殊指令,关闭所有中断

ldr   r9, =0xe000ed00                  @ CPUID register address

ldr   r9, [r9]                         //CPUID基址寄存器,参考手册(周立功)-P80

bl    __lookup_processor_type             @ r5=procinfo r9=cupid              //head-common.S

movs       r10, r5                         @ invalid processor (r5=0)?

beq  __error_p                            @ yes, error 'p'

bl    __lookup_machine_type        @ r5=machinfo

movs       r8, r5                           @ invalid machine (r5=0)?

beq  __error_a                     @ yes, error 'a'

badr lr, __after_proc_init              @ return (PIC) address         //提前暂存lr的值

ARM(   add  pc, r10, #PROCINFO_INITFUNC       )      //R10处偏移16个字节,然后赋给PC

//相当于跳转到下面的__v7m_setup

ENDPROC(stext)

__after_proc_init:

ldr   pc,__switch_data           //将PC 指针赋值到__switch_data标号地址处,实际执行的

ENDPROC(__after_proc_init)      //是在__mmap_switched这个标号处

.ltorg

#include "head-common.S"          //末尾包含下面的文件

1.2   head-common.S

文件在arch\arm\kernel\head-common.S,有__switch_data、__mmap_switched、__error_p、__error_a、__error、__lookup_processor_type、C语言的lookup_processor_type、__lookup_machine_type  、C语言的lookup_machine_type、__vet_atags等组成,这里只列出上面调用要使用的查找处理器类型和查找机器类型。

_lookup_processor_type:                     //r9是刚从CPU基址寄存器中取出的值

ARM(   adr   r3, 3f             )      //执行此句后,r3的地址是后面标号3处的地址

ARM(   ldmda     r3, {r5 - r7}   )//r5,r6,r7依次变为,__proc_info_begin,end,以及

//标号3处的末尾链接地址

sub  r3, r3, r7               @ get offset between virt&phys    //这三行执行虚实地址转换

add  r5, r5, r3               @ convert virt addresses to//r5是proc_info_list结构体地址

add  r6, r6, r3               @ physical address space       //__proc_info_end的自己

1:    ldmia      r5, {r3, r4}                   @ value, mask              //r3是结构体的val变量

and  r4, r4, r9               @ mask wanted bits              //r4是结构体的mask变量

teq   r3, r4

beq  2f                                                                   //相等转到后面的2标号处

add  r5, r5, #PROC_INFO_SZ             @ sizeof(proc_info_list)       //宏定义在asm-offset.h

cmp r5, r6             //结构体可能是个数组,需要全部查找,若r5的地址没有超出end

blo   1b                  //的地址,则继续转到1处理,若最后没找到,r5变为空

mov r5, #0                           @ unknown processor

2:    mov pc, lr

ENDPROC(__lookup_processor_type)

ENTRY(lookup_processor_type)

stmfd      sp!, {r4 - r7, r9, lr}

mov r9, r0             //提供C语言的API结构,r0是传入的参数

bl    __lookup_processor_type

mov r0, r5             //此处的R0是函数的返回值,即传出的参数

ldmfd      sp!, {r4 - r7, r9, pc}

ENDPROC(lookup_processor_type)

.long       __proc_info_begin        //arch/arm/kernel/vmlinux.lds.s中定义

.long       __proc_info_end

3:    .long       .

.long       __arch_info_begin

.long       __arch_info_end

/*

* Lookup machine architecture in the linker-build list of architectures.

* Note that we can't use the absolute addresses for the __arch_info

* lists since we aren't running with the MMU on (and therefore, we are

* not in the correct address space).  We have to calculate the offset.

*

*  r1 = machine architecture number

* Returns:

*  r3, r4, r6 corrupted

*  r5 = mach_info pointer in physical address space

*/

__lookup_machine_type:

adr   r3, 3b

ldmia      r3, {r4, r5, r6}       //r5是__arch_info_begin,r6是end

sub  r3, r3, r4               @ get offset between virt&phys    //虚实地址转换

add  r5, r5, r3               @ convert virt addresses to

add  r6, r6, r3               @ physical address space

1:    ldr   r3, [r5, #MACHINFO_TYPE]      @ get machine type //结构体偏移字节数,见上面的注释

teq   r3, r1                           @ matches loader number?    //与传递给内核的r1相同

beq  2f                         @ found                                     //r3就是结构体中第一个变量nr

add  r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc

cmp r5, r6

blo   1b

mov r5, #0                           @ unknown machine

2:    mov pc, lr

ENDPROC(__lookup_machine_type)

/*

* This provides a C-API version of the above function.

*/

ENTRY(lookup_machine_type)

stmfd      sp!, {r4 - r6, lr}

mov r1, r0             //提供C语言的API结构,r0是传入的参数

bl    __lookup_machine_type

mov r0, r5             //此处的R0是函数的返回值,即传出的参数

ldmfd      sp!, {r4 - r6, pc}

ENDPROC(lookup_machine_type)

1.2.1    lookup_processor_type

1vmlinux.lds.s

文件在arch\arm\kernel\ vmlinux.lds.s

__proc_info_begin = .;                 //include/asm-arm/procinfo.h中定义

*(.proc.info.init)

__proc_info_end = .;

__arch_info_begin = .;                 //include/asm-arm/mach/arch.h 中定义

*(.arch.info.init)

__arch_info_end = .;

2procinfo.h

文件在include/asm-arm/procinfo.h

struct proc_info_list {                   // pro-v7m.S对其实例化

unsigned int           cpu_val;

unsigned int           cpu_mask;

unsigned long        __cpu_mm_mmu_flags; /* used by head.S */

unsigned long        __cpu_io_mmu_flags;    /* used by head.S */

unsigned long        __cpu_flush;          /* used by head.S */

const char              *arch_name;

const char              *elf_name;

unsigned int           elf_hwcap;

const char              *cpu_name;

struct processor      *proc;

struct cpu_tlb_fns   *tlb;

struct cpu_user_fns *user;

struct cpu_cache_fns      *cache;

};

3pro-v7m.S

文件在arch\arm\mm\ pro-v7m.S,内容很多,核心就是.section ".proc.info.init",其它的都是它这个结构体中得成员,如__v7m_setup、cpu_arch_name、cpu_elf_name、cpu_v7m_name、v7m_processor_functions等。

cpu_v7m_name:

.ascii       "ARMv7-M Processor"

.align

.section ".text.init", #alloc, #execinstr

.type v7m_processor_functions, #object

ENTRY(v7m_processor_functions)

.word      v7m_early_abort

.word      cpu_v7m_proc_init

.word      cpu_v7m_proc_fin

.word      cpu_v7m_reset

.word      cpu_v7m_do_idle

.word      cpu_v7m_dcache_clean_area

.word      cpu_v7m_switch_mm

.word      cpu_v7m_set_pte_ext

.word      pabort_noifar

.size v7m_processor_functions, . - v7m_processor_functions

.type cpu_arch_name, #object

cpu_arch_name:

.asciz      "armv7m"

.size cpu_arch_name, . - cpu_arch_name

.type       cpu_elf_name, #object

cpu_elf_name:

.asciz      "v7m"

.size cpu_elf_name, . - cpu_elf_name

.align

.section ".proc.info.init", #alloc, #execinstr

/*

* Match any ARMv7-M processor core.

*/

.type       __v7m_proc_info, #object

__v7m_proc_info:          //E000ED00是CPUID基址寄存器,其中[19:16]读作常量F

.long       0x000f0000           @ Required ID value

.long       0x000f0000           @ Mask for ID

.long   0                     @ proc_info_list.__cpu_mm_mmu_flags

.long   0                     @ proc_info_list.__cpu_io_mmu_flags

b     __v7m_setup         @ proc_info_list.__cpu_flush

.long       cpu_arch_name

.long       cpu_elf_name

.long    HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP

.long       cpu_v7m_name

.long       v7m_processor_functions      @ proc_info_list.proc

.long       0                   @ proc_info_list.tlb

.long       0                   @ proc_info_list.user

.long       0                   @ proc_info_list.cache

.size __v7m_proc_info, . - __v7m_proc_info

1.2.2    lookup_machine_type

1arch.h

文件在include/asm-arm/mach/arch.h

struct machine_desc {                  //在stm3210e_eval.c中实例化

/*

* Note! The first four elements are used

* by assembler code in head.S, head-common.S

*/

unsigned int           nr;          /* architecture number   */

unsigned int           phys_io;  /* start of physical io     */

unsigned int           io_pg_offst;    /* byte offset for io

* page tabe entry  */

const char              *name;           /* architecture name      */

unsigned long        boot_params;  /* tagged list          */

unsigned int           video_start;     /* start of video RAM    */

unsigned int           video_end;      /* end of video RAM     */

unsigned int           reserve_lp0 :1;       /* never has lp0      */

unsigned int           reserve_lp1 :1;       /* never has lp1      */

unsigned int           reserve_lp2 :1;       /* never has lp2      */

unsigned int           soft_reboot :1;       /* soft reboot         */

void               (*fixup)(struct machine_desc *,

struct tag *, char **,

struct meminfo *);

void               (*map_io)(void);/* IO mapping function     */

void               (*init_irq)(void);

struct sys_timer      *timer;           /* system tick timer       */

void               (*init_machine)(void);

};

/*

* Set of macros to define architecture features.  This is built into

* a table by the linker.

*/

#define MACHINE_START(_type,_name)                 \

static const struct machine_desc __mach_desc_##_type       \

__used                                             \

__attribute__((__section__(".arch.info.init"))) = {    \

.nr          = MACH_TYPE_##_type,          \

.name             = _name,

#define MACHINE_END                          \

};

2stm3210e_eval.c

文件在arch\arm\mach-stm3210e_eval\ stm3210e_eval.c

MACHINE_START(STM3210E_EVAL, "STM3210E-EVAL")

/* Maintainer: MCD Application TEAM */                               /* Status */

.fixup             = stm3210e_eval_fixup,                             //OK

.boot_params  = CONFIG_EXTERNAL_RAM_BASE + 0x100,                     //OK

.init_irq   = nvic_init_irq,                                  //OK

.timer             = &stm3210e_eval_timer,                                 //OK

.init_machine  = stm3210e_eval_init,                                //OK

MACHINE_END

3match-type.h

文件在include/asm-arm/mach-type.h

#define MACH_TYPE_STM3210E_EVAL        2189

1.3   __v7m_setup

文件在arch\arm\mm\ pro-v7m.S

/*

* __v7m_setup

*

* Initialise TLB, Caches, and MMU state ready to switch the MMU

* on.  Return in r0 the new CP15 C1 control register setting.

*

* We automatically detect if we have a Harvard cache, and use the

* Harvard cache control instructions insead of the unified cache

* control instructions.

*

* This should be able to cover all ARMv7-M cores.

*

* It is assumed that:

* - cache type register is implemented

*/

__v7m_setup:

@ Configure the vector table base address    //配置中断向量偏移

ldr   r0, =0xe000ed08           @ vector table base address

ldr   r12, =vector_table

str    r12, [r0]

@ Lower the priority of the SVC and PendSV exceptions

ldr   r0, =0xe000ed1c    //设置SVC、PendSV的中断优先级都为128

mov r5, #0x80000000

str    r5, [r0]           @ set SVC priority

ldr   r0, =0xe000ed20

mov r5, #0x00800000

str    r5, [r0]           @ set PendSV priority

@ SVC to run the kernel in this mode

badr r0, 1f

ldr   r5, [r12, #11 * 4]   @ read the SVC vector entry

str    r0, [r12, #11 * 4]   @ write the temporary SVC vector entry

mov r6, lr                     @ save LR

mov r7, sp                    @ save SP

#if !defined(CONFIG_XIP_KERNEL)

ldr   sp, =__v7m_setup_stack_top

#endif

cpsie       i

svc   #0                  //呼叫系统服务,权威指南-P182,暂时没找到?

1: cpsid       i

str    r5, [r12, #11 * 4]   @ restore the original SVC vector entry

mov lr, r6                     @ restore LR

mov sp, r7                    @ restore SP

@ Special-purpose control register

mov r0, #1                           //还是进入特权级的线程模式,主堆栈?

msr  control, r0             @ Thread mode has unpriviledged access

@ Configure the System Control Register

ldr   r0, =0xe000ed10           @ system control register

ldr   r12, [r0]                       //不知道是干啥,不确定是否在E000 ED10上

orr   r12, #1 << 9          @ STKALIGN

str    r12, [r0]                //E000 ED14的这个位倒是为了对齐双字节,指南-306

mov pc, lr                     //之前的lr值赋给PC,即PC转到那里执行

ENDPROC(__v7m_setup)

1.4   __switch_data

文件在arch\arm\kernel\head-common.S

.type       __switch_data, %object

__switch_data:

.long       __mmap_switched

.long       __data_loc                    @ r4

.long       __data_start                  @ r5

.long       _edata_loc                    @ r6 //added to determine the size of data segment to be copied.

.long       __bss_start                    @ r6

.long       _end                            @ r7

.long       processor_id                 @ r4

.long       __machine_arch_type           @ r5

.long       __atags_pointer                    @ r6

#ifdef CONFIG_CPU_CP15

.long       cr_alignment                 @ r7

#else

.long       0                          @ r7

#endif

.long       init_thread_union + THREAD_START_SP @ sp

/*

* The following fragment of code is executed with the MMU on in MMU mode,

* and uses absolute addresses; this is not position independent.

*

*  r0  = cp#15 control register

*  r1  = machine ID

*  r2  = atags pointer

*  r9  = processor ID

*/

__mmap_switched:        //从__v7m_setup出来以后,转到这里

adr   r3, __switch_data + 4

ldmia      r3!, {r4, r5, r6}

cmp r4, r5                           @ Copy data segment if needed

beq  2f

1:    ldr   fp, [r4], #4            //fp是r11

str    fp, [r5], #4

cmp r4, r6

bne  1b

2:    ldmia      r3!,{r6,r7}                   @load __bss_start to r6 and _end to r7

mov fp, #0                           @ Clear BSS (and zero fp)

1:    cmp r6, r7

itt    cc                  //itt相当于if-then

strcc fp, [r6],#4

bcc  1b

ARM(   ldmia      r3, {r4, r5, r6, r7, sp})

str    r9, [r4]                  @ Save processor ID被赋值

str    r1, [r5]                  @ Save machine type被赋值

str    r2, [r6]                  @ Save atags pointer被赋值

bic   r4, r0, #CR_A               @ Clear 'A' bit              这句貌似没用?

#if !defined (CONFIG_CPU_V7M)

stmia       r7, {r0, r4}                   @ Save control register values

#endif

@2: b     2b

b     start_kernel            //跳入C语言的函数

ENDPROC(__mmap_switched)

STM32F103 ucLinux开发之二(内核启动汇编代码分析)的更多相关文章

  1. STM32F103 ucLinux开发之四(内核启动后的调试)

    Stm32-uclinux启动后的调试 1.  修改__pfn_to_page使得能够启动 根据STM32F103 ucLinux开发之三(内核启动后不正常)的描述,内核无法启动是选择了平板内存模式后 ...

  2. STM32F103 ucLinux开发之三(内核启动后不正常)(完结)

    STM32F103 ucLinux内核没有完全启动 从BOOT跳转到内核后,执行一长段的汇编语言,然后来到startkernel函数,开启C语言之旅. 但是内核输出不正常,如下所示: Linux ve ...

  3. STM32F103 ucLinux开发BOOT

    STM32F103 ucLinux开发BOOT STM3210E-EVAL官方开发板主芯片STM32F103ZET6: 片内512K Flash,地址0x0800 0000 ~ 0x0807 FFFF ...

  4. STM32F103 ucLinux开发之一(BOOT分析及源码)

    STM32F103 ucLinux开发BOOT STM3210E-EVAL官方开发板主芯片STM32F103ZET6: 片内512K Flash,地址0x0800 0000 ~ 0x0807 FFFF ...

  5. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  6. start_kernel之前的汇编代码分析

    start_kernel之前的汇编代码分析 Boot中执行下面两句话之后,进入uclinux内核. theKernel = (void (*)(int, int, unsigned int))((ui ...

  7. linux内核中链表代码分析---list.h头文件分析(一)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...

  8. 一个简单C程序的汇编代码分析

    几个重要的寄存器 eip - 用于存放当前所执行的指令地址 esp - 栈(顶)指针寄存器 ebp - 基址(栈底)指针寄存器 简单的C程序 int g(int x) { ; } int f(int ...

  9. Linux内核源码分析--内核启动之(2)Image内核启动(汇编部分)(Linux-3.0 ARMv7) 【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-4938389.html 在完成了zImage自解压之后,就跳转到了解压后的内核(也就是vmlinux的bin ...

随机推荐

  1. img底部空白以及多余的空白文本节点解决方案

    1:img底部有空白的问题 img的css属性display的默认值是inline,这样会导致img的vertical-align的默认值是 baseline; baseline又不是bottom,只 ...

  2. js 两个小括号 ()() 的用法

    实现一个函数fn, 使fn(1)(2)的结果为两个参数的和,刚开始没反应过来,其实细细一想第二个括号就是函数再调用的问题,废话不多说,代码奉上: var fn = function(n) { func ...

  3. JavaScript 数组对象常用属性

    concat() 用于连接两个或多个数组.该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. var a = ["aa","ccc"]; var b ...

  4. Web前端面试指导(十九):CSS样式-如何清除元素浮动?

    题目点评 本题属于比较常问的题目,也是在网页设计中经常遇到的问题,面试官希望通过这样的面试题来了解你对网页设计的基本功底,如果这样的题目答不出来,必会让面试官大失所望,面试成功的概率是非常小的. 答题 ...

  5. CSS性能优化新属性:will-change

    ---恢复内容开始--- will-change属性通过告诉浏览器什么属性.什么元素将会发生变化,可以对这些操作进行可能性的优化,由此提高CSS动画的执行效率. 这个属性可以有4个值: auto: 实 ...

  6. 实例解析Docker数据卷+数据卷容器+flocker数据共享+DockerHub操作

    Docker内部数据管理和Docker之间的数据共享为数据卷和数据卷容器,实例解析1.将本地的文件作为容器的数据卷,2.数据卷flocker插件实现容器集群(或者Docker Swarm)的数据共享3 ...

  7. [转载]hive中order by,sort by, distribute by, cluster by作用以及用法

    1. order by     Hive中的order by跟传统的sql语言中的order by作用是一样的,会对查询的结果做一次全局排序,所以说,只有hive的sql中制定了order by所有的 ...

  8. 形象解释C#、Net、Asp.net

    下文是写给计算机小白的,尽量用形象的语言来让她们明白这些比较抽象的概念. -------------------------------------- C#: 你和美国人说话要说英语 和中国人说话说汉 ...

  9. kafka leader平衡策略

    1.1个partition的默认leader是replicas中的第一个replica 2.kafka controller会启动一个定时的check线程,kafka默认是5min周期,mafka是3 ...

  10. 任务十五:零基础JavaScript编码(三)

    任务目的 在上一任务基础上继续JavaScript的体验 接触一下JavaScript中的高级选择器 学习JavaScript中的数组对象遍历.读写.排序等操作 学习简单的字符串处理操作 任务描述 参 ...