Arm linux启动分析.docx

上传人:b****7 文档编号:9376478 上传时间:2023-02-04 格式:DOCX 页数:17 大小:23.79KB
下载 相关 举报
Arm linux启动分析.docx_第1页
第1页 / 共17页
Arm linux启动分析.docx_第2页
第2页 / 共17页
Arm linux启动分析.docx_第3页
第3页 / 共17页
Arm linux启动分析.docx_第4页
第4页 / 共17页
Arm linux启动分析.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

Arm linux启动分析.docx

《Arm linux启动分析.docx》由会员分享,可在线阅读,更多相关《Arm linux启动分析.docx(17页珍藏版)》请在冰豆网上搜索。

Arm linux启动分析.docx

Armlinux启动分析

Armlinux启动分析

(1)

下周准备做linux启动的技术讲座,在这里我慢慢整理下自己的材料,这次我写的是Image的启动过程,也即使zImage解压缩结束后的启动代码,这时候的代码开始地址仍然是0x30008000,下面我结合代码来讲吧:

Image的启动代码是在/arch/arm/kernel/head.S中的:

/*

 * linux/arch/arm/kernel/head.S

 * Kernelstartupcodeforall32-bitCPUs

 */

 /*内核启动入口点

 *Kernelstartupentrypoint.

 *这里通常在解压后直接调用。

 *处理器基本状态要求:

 *MMU关闭,D-cach关闭,I-cache不用关系;

 *r0=0,r1=系统号(machinenumber)

 *这段代码几乎是位置无关的。

 *如果链接内核在0xc0008000,调用的地址为相应的物理地址__pa(0xc0008000)。

 *r1的系统号参考arch/arm/tools/mach-types文件的列表。

 *尽量不要在这里添加系统号相关的代码,那应该放在bootloader的代码中。

 *保持这里的代码的整洁。

 */

 __INIT

 .type stext,%function

/*――――――――――――――――――――――――――――――――――――――――――――――

这个地方就是kernel的入口点

――――――――――――――――――――――――――――――――――――――――――――――*/

ENTRY(stext)

 msr cpsr_c,#PSR_F_BIT|PSR_I_BIT|MODE_SVC@ensuresvcmode

      @andirqsdisabled

/*―――――――――――――――――――――――――――――――――――――――――――――― 

  调用__lookup_processor_type检查现在运行的cpu的ID值和linux编译支持的

id值是否相等。

――――――――――――――――――――――――――――――――――――――――――――――*/

 bl __lookup_processor_type  @r5=procinfor9=cpuid

/*――――――――――――――――――――――――――――――――――――――――――――――

   从该函数返回后,寄存器内容如下:

   R9 =cpuID

   R5=pointertoprocessorstructure

 

   详细的内容请看__lookup_processor_type的分析*/

  .type __lookup_processor_type,%function

__lookup_processor_type:

/*――――――――――――――――――――――――――――――――――――――――――――――  

  把标号2的地址送给r3,3f=lable3forward 

――――――――――――――――――――――――――――――――――――――――――――――*/

 adr r3,3f

/*――――――――――――――――――――――――――――――――――――――――――――――

  把r3指向内存的地址的内容赋值给r5,r6,r9

   所以,参照标号3处的声明,我们可以知道:

   __proc_info_begin    r5

   __proc_info_end      r6

   3b                   r9

 

   __proc_info_end和__proc_info_begin这两个标号都是在

/linux/arch/arm/vmlinux.ld这个脚本中定义的。

在连接的时候,ld会把相应cpu信息

proc_info放到这两个标号之间。

       __proc_info_begin=.;

                       *(.proc.info)

       __proc_info_end=.;

――――――――――――――――――――――――――――――――――――――――――――――*/

 ldmda r3,{r5,r6,r9} @ldmda弹栈顺序是从右到左,[r3]->r9,[r3-4]->r6,[r3-8]->r5

/*r3=标号3的加载地址地址,r9=标号3的连接地址,r3是根据pc值确定的,r9是链接阶段就确定的是链接地址*/

 sub r3,r3,r9   @getoffsetbetweenvirt&phys

 //r3=加载地址和连接地址的差值

 //现在,r5=__proc_info_begin的加载地址,即在RAM中的地址

 add r5,r5,r3   @convertvirtaddressesto

 add r6,r6,r3   @physicaladdressspace

 mrc p15,0,r9,c0,c0 @getprocessorid协处理器指令获取cpuid号r9=0x41807202(sep4020)

/*――――――――――――――――――――――――――――――――――――――――――――――

   在本例中,r5 = _arm720_proc_info这个标记定义在

linux/arch/arm/mm/proc-arm720.S

__arm720_proc_info:

       .long  0x41807200      r3=cpu_value

       .long  0xffffff00      r4=cpu_mask

       .long  0x00000c1e      mmuflags,一级段描述符

       b      __arm720_setup

                     .

                     .

――――――――――――――――――――――――――――――――――――――――――――――*/

//ldmia弹栈顺序是从左到右,[r5]->r3,[r5+4]->r4,即低地址的内容放到低编号的寄存器,高地址的内容放到高编号的寄存器,指令结束后r5的指依然为_arm720_proc_info

1:

 ldmia r5,{r3,r4}   @value,mask 

 and r4,r4,r9   @maskwantedbits

//将r9屏上0xffffff00看sep4020是否是arm720t的内核

 teq r3,r4

 beq 2f    @若是arm720t内核则直接跳转到标签2

/*――――――――――――――――――――――――――――――――――――――――――――――

  proc_info_list定义在linux/include/asm-arm/procinfo.h

 

   structproc_info_list{

 unsignedint  cpu_val;

 unsignedint  cpu_mask;

 unsignedlong  __cpu_mmu_flags; //usedbyhead.S

 unsignedlong  __cpu_flush;  //usedbyhead.S

 constchar  *arch_name;

 constchar  *elf_name;

 unsignedint  elf_hwcap;

 constchar  *cpu_name;

 structprocessor *proc;

 structcpu_tlb_fns *tlb;

 structcpu_user_fns *user;

 structcpu_cache_fns *cache;

};

   每一项都是4个字节,所以sizeof(proc_info_list)=48byte

――――――――――――――――――――――――――――――――――――――――――――――*/

 add r5,r5,#PROC_INFO_SZ  @sizeof(proc_info_list)=48

 cmp r5,r6

 blo 1b

 mov r5,#0    @unknownprocessor

2:

 mov pc,lr

/*

 *ThisprovidesaC-APIversionoftheabovefunction.

 */

ENTRY(lookup_processor_type)

 stmfd sp!

{r4-r6,r9,lr}

 bl __lookup_processor_type

 mov r0,r5

 ldmfd sp!

{r4-r6,r9,pc}

/*

 *Lookininclude/asm-arm/procinfo.handarch/arm/kernel/arch.[ch]for

 *moreinformationaboutthe__proc_infoand__arch_infostructures.

 */

 .long __proc_info_begin

 .long __proc_info_end

3:

 .long .

 .long __arch_info_begin

 .long __arch_info_end

   

/*―――――――――――――从__lookup_processor_type返回―――――――――――――――――――――――――――――――――*/

 movs r10,r5    @是有效720t核吗 (r5=0)?

 beq __error_p   @yes,error'p'

/*――――――――――――――――――――――――――――――――――――――――――――――

  __lookup_machine_type通过R1寄存器,判断体系类型,R1=machine

architecturenumber

――――――――――――――――――――――――――――――――――――――――――――――*/

 bl __lookup_machine_type  @r5=machinfo

/*――――――――――――――――――――――――――――――――――――――――――――――*/

/* r1=machinearchitecturenumber

 *Returns:

 * r3,r4,r6corrupted

 * r5=mach_infopointerinphysicaladdressspace

 */

 .type __lookup_machine_type,%function

__lookup_machine_type:

 adr r3,3b

/*――――――――――――――――――――――――――――――――――――――――――――――

  把r3指向内存的地址的内容赋值给r4,r5,r6

   所以,参照标号3处的声明,我们可以知道:

   3b                  r4

   __arch_info_begin r5

  __arch_info_end  r6

  

   __arch_info_end和__arch_info_begin这两个标号都是在

/linux/arch/arm/vmlinux.ld这个脚本中定义的。

在连接的时候,ld会把相应体系架构

arch_info放到这两个标号之间。

       __arch_info_begin=.;

     *(.arch.info.init)

   __arch_info_end=.;

――――――――――――――――――――――――――――――――――――――――――――――*/

 ldmia r3,{r4,r5,r6}

 sub r3,r3,r4   @getoffsetbetweenvirt&phys

 //r5=__arch_info_begin的加载地址

 add r5,r5,r3   @convertvirtaddressesto

 add r6,r6,r3   @physicaladdressspace

/*――――――――――――――――――――――――――――――――――――――――――――――

   __arch_info_begin和__arch_info_end 的类型都是struct machine_desc。

其实

就是指向一个machine_desc结构首尾的两个地址标号。

   structmachine_desc定义在linux/include/asm-arm/mach/arch.h中

   structmachine_desc{

       /*

        *Note!

Thefirstfourelementsareused

        *byassemblercodeinhead.S

        */

   unsignedint  nr;  /*architecturenumber */

 unsignedint__deprecatedphys_ram; /*startofphysicalram*/

 unsignedint  phys_io; /*startofphysicalio */

 unsignedint  io_pg_offst; /*byteoffsetforio

      *pagetabeentry */

 constchar  *name;  /*architecturename */

 unsignedlong  boot_params; /*taggedlist  */

 unsignedint  video_start; /*startofvideoRAM */

 unsignedint  video_end; /*endofvideoRAM */

 unsignedint  reserve_lp0:

1; /*neverhaslp0 */

 unsignedint  reserve_lp1:

1; /*neverhaslp1 */

 unsignedint  reserve_lp2:

1; /*neverhaslp2 */

 unsignedint  soft_reboot:

1; /*softreboot  */

 void   (*fixup)(structmachine_desc*,

     structtag*,char**,

     structmeminfo*);

 void   (*map_io)(void);/*IOmappingfunction */

 void   (*init_irq)(void);

 structsys_timer *timer;  /*systemticktimer */

 void   (*init_machine)(void);

};

而对于我们的SEP4020其真正的定义是在/arch/arm/mach-sep4020/4020.c中

MACHINE_START(GFD4020,"4020board")

 .phys_io =0x10000000,

 .io_pg_offst =((0xe0000000)>>18)&0xfffc,

 .boot_params =0x30000100,

 .fixup  =fixup_gfd4020,

 .map_io  =sep4020_map_io,

 .init_irq = sep4020_init_irq,

 .init_machine =sep4020_init,

 .timer  =&sep4020_timer,

MACHINE_END

   看到这里,我们就不难明白下边这条指令了,structmachine_desc中第一个就是

nr,即architecturenumber

r3=MACH_TYPE_GFD4020

――――――――――――――――――――――――――――――――――――――――――――――*/

1:

 ldr r3,[r5,#MACHINFO_TYPE] @getmachinetype,MACHINFO_TYPE=0

//r1是由解压缩程序/arch/arm/boot/compressed/head.S最后传过来的,或者是uboot传过来的体系结构号

 teq r3,r1    @matchesloadernumber?

 beq 2f    @found

 add r5,r5,#SIZEOF_MACHINE_DESC @nextmachine_desc

 cmp r5,r6

 blo 1b

 mov r5,#0    @unknownmachine

2:

 mov pc,lr

/*―――――――――――――――――从__lookup_machine_type返回―――――――――――――――――――――――――――――*/

 movs r8,r5    @invalidmachine(r5=0)?

是不是我们的SEP4020系统结构

 beq __error_a   @yes,error'a'

/*――――――――――――――――――――――――――――――――――――――――――――――

  设置mmu之前,设置临时内核页表

――――――――――――――――――――――――――――――――――――――――――――――*/

 bl __create_page_tables

/*――――――――――――――――――――――――――――――――――――――――――――――

/* 我们在这里只映射内核启动的临时页表

 *Setuptheinitialpagetables. Weonlysetupthebarest

 *amountwhicharerequiredtogetthekernelrunning,which

 *generallymeansmappinginthekernelcode.

 *

 *r8 =machinfo 体系结构信息

 *r9 =cpuid    cpu的ID

 *r10=procinfo cpu信息

 *

 *Returns:

 * r0,r3,r6,r7corrupted

 * r4=physicalpagetableaddress

 */

 .type __create_page_tables,%function

__create_page_tables:

/*――――――――――――――――――――――――――――――――――――――――――――――*/

//Pageoffset:

3GB 内核页表的偏移在/inculde/asm/memory.h

#definePAGE_OFFSET  UL(0xc0000000)

#ifndef__virt_to_phys

#define__virt_to_phys(x) ((x)-PAGE_OFFSET+PHYS_OFFSET)

#define__phys_to_virt(x) ((x)-PHYS_OFFSET+PAGE_OFFSET)

#endif

而这其中的PHYS_OFFSET则是我们需要在我们的SEP4020的定义自己的主存ram的基址的物理地址,我们是在/include/asm-arm/arch-sep4020/memory.h中定义的

#definePHYS_OFFSET UL(0x30000000)

/*TEXT_OFFSET是在在arch/arm/Makefile第140行,有

TEXT_OFFSET:

=$(textofs-y)

第90行有

textofs-y:

=0x00008000

所以TEXT_OFFSET:

=0x00008000

在153行有exportTEXT_OFFSET将此变量输出。

*/

#defineKERNEL_RAM_ADDR (PAGE_OFFSET+TEXT_OFFSET) @其中TEXT_OFFSET=0x8000

//swapper_pg_dir是放启动时的临时页表的页表基址(虚地址)

 .globl swapper_pg_dir

 .equ swapper_pg_dir,KERNEL_RAM_ADDR-0x4000

//这个宏就是根据内核ram首址(虚拟地址)计算出我们内核页表的页表基址(物理地址)

 .macro pgtbl,rd

 ldr \rd,=(__virt_to_phys(KERNEL_RAM_ADDR-0x4000))

 .endm

――――――――――――――――――――――――――――――――――――――――――――――*/

 pgtbl r4    @pagetableaddress

//这样r4=内核页表的页表基址(物理地址)

 /*

 *Clearthe16Klevel1swapperpagetable

 */

 mov r0,r4

 mov r3,#0

 //r6=内核的KERNEL_RAM_ADDR

 add r6,r0,#0x4000

 //首先对16k的一级页表内容清0

1:

 str r3,[r0],#4

 str r3,[r0],#4

 str r3,[r0],#4

 str r3,[r0],#4

 teq r0,r6

 bne 1b

//PROCINFO_MMUFLAGS=8;这样r7=0x00000c1e      mmuflags,一级段描述符,在proc-arm720.S中定义

 ldr r7,[r10,#PROCINFO_MMUFLAGS

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 制度规范

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1