Linux内核启动流程分析二文档格式.docx

上传人:b****3 文档编号:6451879 上传时间:2023-05-06 格式:DOCX 页数:27 大小:39.94KB
下载 相关 举报
Linux内核启动流程分析二文档格式.docx_第1页
第1页 / 共27页
Linux内核启动流程分析二文档格式.docx_第2页
第2页 / 共27页
Linux内核启动流程分析二文档格式.docx_第3页
第3页 / 共27页
Linux内核启动流程分析二文档格式.docx_第4页
第4页 / 共27页
Linux内核启动流程分析二文档格式.docx_第5页
第5页 / 共27页
Linux内核启动流程分析二文档格式.docx_第6页
第6页 / 共27页
Linux内核启动流程分析二文档格式.docx_第7页
第7页 / 共27页
Linux内核启动流程分析二文档格式.docx_第8页
第8页 / 共27页
Linux内核启动流程分析二文档格式.docx_第9页
第9页 / 共27页
Linux内核启动流程分析二文档格式.docx_第10页
第10页 / 共27页
Linux内核启动流程分析二文档格式.docx_第11页
第11页 / 共27页
Linux内核启动流程分析二文档格式.docx_第12页
第12页 / 共27页
Linux内核启动流程分析二文档格式.docx_第13页
第13页 / 共27页
Linux内核启动流程分析二文档格式.docx_第14页
第14页 / 共27页
Linux内核启动流程分析二文档格式.docx_第15页
第15页 / 共27页
Linux内核启动流程分析二文档格式.docx_第16页
第16页 / 共27页
Linux内核启动流程分析二文档格式.docx_第17页
第17页 / 共27页
Linux内核启动流程分析二文档格式.docx_第18页
第18页 / 共27页
Linux内核启动流程分析二文档格式.docx_第19页
第19页 / 共27页
Linux内核启动流程分析二文档格式.docx_第20页
第20页 / 共27页
亲,该文档总共27页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Linux内核启动流程分析二文档格式.docx

《Linux内核启动流程分析二文档格式.docx》由会员分享,可在线阅读,更多相关《Linux内核启动流程分析二文档格式.docx(27页珍藏版)》请在冰点文库上搜索。

Linux内核启动流程分析二文档格式.docx

/* 

初始化代码段*/

_stext 

.;

_sinittext 

*(.init.text)

_einittext 

__proc_info_begin 

*(.proc.info.init)

__proc_info_end 

__arch_info_begin 

*(.arch.info.init)

__arch_info_end 

__tagtable_begin 

*(.taglist.init)

__tagtable_end 

ALIGN(16);

__setup_start 

*(.init.setup)

__setup_end 

__early_begin 

*(.early_param.init)

__early_end 

__initcall_start 

*(.initcall1.init)

*(.initcall2.init)

*(.initcall3.init)

*(.initcall4.init)

*(.initcall5.init)

*(.initcall6.init)

*(.initcall7.init)

__initcall_end 

__con_initcall_start 

*(.con_initcall.init)

__con_initcall_end 

__security_initcall_start 

*(.security_initcall.init)

__security_initcall_end 

ALIGN(32);

__initramfs_start 

usr/built-in.o(.init.ramfs)

__initramfs_end 

ALIGN(64);

__per_cpu_start 

*(.data.percpu)

__per_cpu_end 

#ifndef 

CONFIG_XIP_KERNEL

__init_begin 

_stext;

*(.init.data)

ALIGN(4096);

__init_end 

#endif

}

下面开始代码\arch\arm\kernel\head.S的注释:

开始分析前先看下一点基础知识:

1. 

kernel运行的史前时期和内存布局

在arm平台下,zImage.bin压缩镜像是由bootloader加载到物理内存,然后跳到zImage.bin里一段程序,它专门于将被压缩的kernel解压缩到KERNEL_RAM_PADDR开始的一段内存中,接着跳进真正的kernel去执行。

该kernel的执行起点是stext函数,定义于arch/arm/kernel/head.S。

此时内存的布局如下图所示

在开发板3c2410中,SDRAM连接到内存控制器的Bank6中,它的开始内存地址是0x30000000,大小为64M,即0x20000000。

ARM 

kernel将SDRAM的开始地址定义为PHYS_OFFSET。

经bootloader加载kernel并由自解压部分代码运行后,最终kernel被放置到KERNEL_RAM_PADDR(=PHYS_OFFSET 

TEXT_OFFSET,即0x30008000)地址上的一段内存,经此放置后,kernel代码以后均不会被移动。

在进入kernel代码前,即bootloader和自解压缩阶段,ARM未开启MMU功能。

因此kernel启动代码一个重要功能是设置好相应的页表,并开启MMU功能。

为了支持MMU功能,kernel镜像中的所有符号,包括代码段和数据段的符号,在链接时都生成了它在开启MMU时,所在物理内存地址映射到的虚拟内存地址。

以arm 

kernel第一个符号(函数)stext为例,在编译链接,它生成的虚拟地址是0xc0008000,而放置它的物理地址为0x30008000(还记得这是PHYS_OFFSET+TEXT_OFFSET吗?

)。

实际上这个变换可以利用简单的公式进行表示:

va 

pa 

– 

PHYS_OFFSET 

PAGE_OFFSET。

Arm 

linux最终的kernel空间的页表,就是按照这个关系来建立。

之所以较早提及arm 

linux 

的内存映射,原因是在进入kernel代码,里面所有符号地址值为清一色的0xCXXXXXXX地址,而此时ARM未开启MMU功能,故在执行stext函数第一条执行时,它的PC值就是stext所在的内存地址(即物理地址,0x30008000)。

因此,下面有些代码,需要使用地址无关技术。

__HEAD 

/*该宏定义了下面的代码位于"

.head.text"

段内*/

.type 

stext, 

%function 

/*声明stext为函数*/

ENTRY(stext) 

/*第二阶段的入口地址*/

setmode 

PSR_F_BIT 

PSR_I_BIT 

SVC_MODE, 

r9 

ensure 

svc 

mode 

and 

irqs 

disabled 

进入超级权限模式,关中断

/*从协处理器CP15,C0读取CPU 

ID,然后在__proc_info_begin开始的段中进行查找,如果找到,则返回对应处理器相关结构体在物理地址空间的首地址到r5,最后保存在r10中*/

mrc 

p15, 

r9, 

c0, 

c0 

get 

processor 

id 

取出cpu 

id

bl 

__lookup_processor_type 

r5=procinfo 

r9=cpuid

/**********************************************************************/ 

__lookup_processor_type函数的具体解析开始(\arch\arm\kernel\ 

head-common.S)

在讲解该程序段之前先来看一些相关知识,内核所支持的每一种CPU 

类型都由结构体proc_info_list来描述。

该结构体在文件arch/arm/include/asm/procinfo.h 

中定义:

struct 

unsigned 

int 

cpu_val;

cpu_mask;

long 

__cpu_mm_mmu_flags;

used 

by 

head.S 

*/ 

__cpu_io_mmu_flags;

__cpu_flush;

const 

char 

*arch_name;

*elf_name;

elf_hwcap;

*cpu_name;

*proc;

cpu_tlb_fns 

*tlb;

cpu_user_fns 

*user;

cpu_cache_fns 

*cache;

};

对于 

arm920 

来说,其对应结构体在文件 

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

中初始化。

.section 

"

.proc.info.init"

 

#alloc, 

#execinstr 

/*定义了一个段,下面的结构体存放在该段中*/

__arm920_proc_info,#object 

/*声明一个结构体对象*/

__arm920_proc_info:

/*为该结构体赋值*/

.long 

0x41009200

0xff00fff0

PMD_TYPE_SECT 

\

PMD_SECT_BUFFERABLE 

PMD_SECT_CACHEABLE 

PMD_BIT4 

PMD_SECT_AP_WRITE 

PMD_SECT_AP_READ

__arm920_setup

…………………………………

表明了该结构在编译后存放的位置。

在链接文件 

arch/arm/kernel/vmlinux.lds 

中:

SECTIONS 

#ifdef 

CONFIG_XIP_KERNEL 

XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);

#else 

PAGE_OFFSET 

TEXT_OFFSET;

#endif 

.text.head 

*(.text.head) 

Init 

code 

data 

INIT_TEXT 

*(.proc.info.init) 

*(.arch.info.init) 

*(.taglist.init) 

……………………………… 

} 

所有CPU类型对应的被初始化的 

proc_info_list结构体都放在 

__proc_info_begin和__proc_info_end之间。

*

cpuid

Returns:

r5 

proc_info 

pointer 

in 

physical 

address 

space

cpuid 

(preserved)

*/

__lookup_processor_type:

adr 

r3, 

3f 

@r3存储的是标号 

的物理地址(由于没有启用 

mmu 

,所以当前肯定是物理地址) 

ldmia 

{r5 

r7} 

R5=__proc_info_begin,r6=__proc_info_end,r7=标号4处的虚拟地址,即4:

处的地址

add 

#8 

得到4处的物理地址,刚好是跳过两条指令

sub 

r7 

offset 

between 

virt&

phys得到虚拟地址和物理地址之间的offset

/*利用offset 

,将 

和 

r6 

中保存的虚拟地址转变为物理地址*/

r5, 

r3 

convert 

virt 

addresses 

to

r6, 

1:

{r3, 

r4} 

value, 

mask 

r3= 

cpu_val 

r4= 

cpu_mask

r4, 

wanted 

bits;

中存放的是先前读出的 

ID 

,此处屏蔽不需要的位

teq 

r4 

查看代码和CPU 

硬件是否匹配( 

比如想在arm920t上运行为cortex-a8编译的内核?

不让)

beq 

2f 

如果相等则跳转到标号2处,执行返回指令

#PROC_INFO_SZ 

sizeof(proc_info_list结构的长度,在这等于48)如果没找到, 

跳到下一个proc_info_list 

cmp 

判断是不是到了该段的结尾

blo 

1b 

如果没有,继续跳到标号1处,查找下一个

mov 

#0 

unknown 

,如果到了结尾,没找到匹配的,就把0赋值给r5,然后返回

2:

pc, 

lr 

找到后返回,r5指向找到的结构体

ENDPROC(__lookup_processor_type)

.align 

2

3:

__proc_info_begin

__proc_info_end

4:

@“.”表示当前这行代码编译连接后的虚拟地址

__arch_info_begin

__arch_info_end

__lookup_processor_type函数的具体解析结束(\arch\arm\kernel\ 

movs 

r10, 

invalid 

(r5=0)?

__error_p 

yes, 

error 

'

p'

/*机器 

ID是由u-boot引导内核是通过thekernel第二个参数传递进来的,现在保存在r1中,在__arch_info_begin开始的段中进行查找,如果找到,则返回machine对应相关结构体在物理地址空间的首地址到r5,最后保存在r8中。

__lookup_machine_type 

r5=machinfo

__lookup_machine_type函数的具体解析开始(\arch\arm\kernel\ 

每一个CPU 

平台都可能有其不一样的结构体,描述这个平台的结构体是 

这个结构体在文件arch/arm/include/asm/mach/arch.h 

nr;

architecture 

number 

phys_io;

start 

of 

io 

对于平台smdk2410 

来说其对应 

结构在文件linux/arch/arm/mach-s3c2410/mach-smdk2410.c中初始化:

MACHINE_START(SMDK2410, 

SMDK2410"

) 

.phys_io 

S3C2410_PA_UART, 

.io_pg_offst 

(((u32)S3C24XX_VA_UART) 

>

18) 

&

0xfffc, 

.boot_params 

S3C2410_SDRAM_PA 

0x100, 

.map_io 

smdk2410_map_io, 

.init_irq 

s3c24xx_init_irq, 

.init_machine 

smdk2410_init, 

.timer 

s3c24xx_timer, 

MACHINE_END 

对于宏MACHINE_START 

在文件 

arch/arm/include/asm/mach/arch.h 

#define 

MACHINE_START(_type,_name) 

static 

__mach_desc_##_type 

__used 

__attribute__((__section__("

.arch.info.init"

))) 

.nr 

MACH_TYPE_##_type, 

.name 

_name, 

)))表明该结构体在并以后存放的位置。

链接脚本文件 

中 

在__arch_info_begin和 

__arch_info_end之间存放了linux内核所支持的所有平台对应的 

结构体。

/*

number

mach_info 

__lookup_machine_type:

4b 

把标号4处的地址放到r3寄存器里面

{r4, 

r6} 

标号4处的虚拟地址 

,r 

6= 

phys 

计算出虚拟地址与物理地址的偏移

/*读取machine_desc结构的 

nr 

参数,对于smdk2410 

来说该值是 

MACH_TYPE_SMDK2410,这个值在文件linux/arch/arm/tools/mach-types 

中:

smdk2410 

ARCH_SMDK2410 

SMDK2410 

193 

ldr 

[r5, 

#MACHINFO_TYPE] 

type

mat

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

当前位置:首页 > PPT模板 > 节日庆典

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2