linux 启动 x,(1)linux启动过程

head.S是linux启动后的第一个文件,主要完成以下功能:

1、检查处理器信息,并保存;

2、检查平台号,并保存;

3、创建页表,并开启MMU功能;

4、对内核data section、bbs section作调整和初始化,保存必要的变量,设置栈指针跳到start_kernel;

实现过程:

//定义进程0的页表基地址,位于内核代码前16k,注意这是一个虚拟地址。

.globl swapper_pg_dir

.equ swapper_pg_dir, TEXTADDR - 0x4000

//这个宏用于计算内核页表的基地址,是物理地址。

.macro pgtbl, rd, phys

adr \rd, stext

sub \rd, \rd, #0x4000

.endm

//定义所属为init段

__INIT

//定义个函数地址

.type stext, %function

ENTRY(stext)

//设置处理器SVC模式,禁止IRQ中断、FIQ中断。

msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC

//查找处理器类型并判断是否有效。

bl __lookup_processor_type  @ r5=procinfo r9=cpuid

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'

//创建页表。

bl __create_page_tables

//把__switch_data地址处的内容放到r13,也就是r13=_mmap_swithced,在__enable_mmu之后会返回到这里执行。要注意这个r13放的可以虚拟地址,在打开MMU之后跳到这。

ldr r13, __switch_data

//在PROCINFO_INITFUNC被调用之后执行_enable_mmu

adr lr, __enable_mmu  @ return (PIC) address

//调用处理器相关的初始化函数(arch/arm/mm/proc-arm920.S -arm920_setup)。

add pc, r10, #PROCINFO_INITFUNC

//

.type __switch_data, %object

__switch_data:

.long __mmap_switched

.long __data_loc   @ r4

.long __data_start   @ r5

.long __bss_start   @ r6

.long _end    @ r7

.long processor_id   @ r4

.long __machine_arch_type  @ r5

.long cr_alignment   @ r6

.long init_thread_union + THREAD_START_SP @ sp

/*

* The following fragment of code is executed with the MMU on, and uses

* absolute addresses; this is not position independent.

*

*  r0  = cp#15 control register

*  r1  = machine ID

*  r9  = processor ID

*/

.type __mmap_switched, %function

__mmap_switched:

//r4=_data_loc,r5=_data_start,r6=_bss_start,r7=_end

adr r3, __switch_data + 4

ldmia r3!, {r4, r5, r6, r7}

//_data_loc==_data_start,不用移动。

cmp r4, r5    @ Copy data segment if needed

1: cmpne r5, r6

ldrne fp, [r4], #4

strne fp, [r5], #4

bne 1b

//清除BSS段。

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

1: cmp r6, r7

strcc fp, [r6],#4

bcc 1b

ldmia r3, {r4, r5, r6, sp}

str r9, [r4]   @ Save processor ID

str r1, [r5]   @ Save machine type

bic r4, r0, #CR_A   @ Clear 'A' bit

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

b start_kernel

从下面开始说上面的子调用:

1、CPU信息和平台信息的检查

/*

* Read processor ID register (CP#15, CR0), and look up in the linker-built

* supported processor list.  Note that we can't use the absolute addresses

* for the __proc_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.

*

* Returns:

* r3, r4, r6 corrupted

* r5 = proc_info pointer in physical address space

* r9 = cpuid

*/

.type __lookup_processor_type, %function

__lookup_processor_type:

//把下面红色的3位置处的地址放到r3,是物理地址。

adr r3, 3f

//把红3放到r9,r5=__proc_info_begin,r6=__proc_info_endldmda r3, {r5, r6, r9}

//计算物理地址与虚拟地址的偏移放到r3.

sub r3, r3, r9   @ get offset between virt&phys

//把r5 r6转化为物理地址。

add r5, r5, r3   @ convert virt addresses to

add r6, r6, r3   @ physical address space

//从协处理器读出cpu的ID放到r9.

mrc p15, 0, r9, c0, c0  @ get processor id

//把proc_info_list里的cpu_val和cpu_mask读到r3和r4.处理器信息存放在(arch/arm/mm/arm/proc-arm920.S cpu_val=0x41009200,cpu_mask=0xff00fff0).判断是否cpu_val==cpu_mask&r9)如果失败r5=0。

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

and r4, r4, r9   @ mask wanted bits

teq r3, r4

beq 2f

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

cmp r5, r6

blo 1b

mov r5, #0    @ unknown processor

2: mov pc, lr

/*

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

*/

//这个是C函数调用的API,如此学一下如何写被C调用的汇编函数。

ENTRY(lookup_processor_type)

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

bl __lookup_processor_type

mov r0, r5

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

/*

* Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for

* more information about the __proc_info and __arch_info structures.

*/

.long __proc_info_begin

.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_processor_type语法格式是完全一样的,把loader传过来的机器号和从内核里定义的相比较看是否相等,如果相等会把这个mach_info存放到r5里,mach_info在文件arch/arm/mach-s3c2410/mach-smdk2410.c里,而机器号在include/asm/mach-type.h里。

.type __lookup_machine_type, %function

__lookup_machine_type:

adr r3, 3b

ldmia r3, {r4, r5, r6}

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?

beq 2f    @ found

add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc

cmp r5, r6

blo 1b

mov r5, #0    @ unknown machine

2: mov pc, lr

/*

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

*/

ENTRY(lookup_machine_type)

stmfd sp!, {r4 - r6, lr}

mov r1, r0

bl __lookup_machine_type

mov r0, r5

ldmfd sp!, {r4 - r6, pc}

2、创建面表

/*

* Setup the initial page tables.  We only setup the barest

* amount which are required to get the kernel running, which

* generally means mapping in the kernel code.

*

* r8  = machinfo

* r9  = cpuid

* r10 = procinfo

*

* Returns:

*  r0, r3, r5, r6, r7 corrupted

*  r4 = physical page table address

*/

.type __create_page_tables, %function

__create_page_tables:

//把SDRAM的物理地址放到r5.

ldr r5, [r8, #MACHINFO_PHYSRAM] @ physram

//用pgtbl宏计算出面表的物理地址,在内核代码前16k

pgtbl r4, r5    @ page table address

/*

* Clear the 16K level 1 swapper page table

*/

//把16K页表内容清0.

mov r0, r4

mov r3, #0

add r6, r0, #0x4000

1: str r3, [r0], #4

str r3, [r0], #4

str r3, [r0], #4

str r3, [r0], #4

teq r0, r6

bne 1b

//从处理器信息结构读出MMU参数。

ldr r7, [r10, #PROCINFO_MMUFLAGS] @ mmuflags

/*

* Create identity mapping for first MB of kernel to

* cater for the MMU enable.  This identity mapping

* will be removed by paging_init().  We use our current program

* counter to determine corresponding section base address.

*/

//为了打开MMU功能时不出问题,把当前物理地址的1Mb范围内与虚拟地址做相等映射。

mov r6, pc, lsr #20   @ start of kernel section

orr r3, r7, r6, lsl #20  @ flags + kernel base

//[r4, r6, lsl #2]代表页表的项所在的地址,这个#2是因为每个页表项占用4个字节,r3代表向相应的页表项地址所填写的内容,也就是要映射的虚拟地址。

str r3, [r4, r6, lsl #2]  @ identity mapping

/*

* Now setup the pagetables for our kernel direct

* mapped region.  We round TEXTADDR down to the

* nearest megabyte boundary.  It is assumed that

* the kernel fits within 4 contigous 1MB sections.

*/

//把内核的前4MB虚拟地址映射到相应的物理地址。

add r0, r4,  #(TEXTADDR & 0xff000000) >> 18

str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]!

add r3, r3, #1 << 20

str r3, [r0, #4]!   @ KERNEL + 1MB

add r3, r3, #1 << 20

str r3, [r0, #4]!   @ KERNEL + 2MB

add r3, r3, #1 << 20

str r3, [r0, #4]   @ KERNEL + 3MB

/*

* Then map first 1MB of ram in case it contains our boot params.

*/

//把内核开始地址映射到物理ram的开始处。

add r0, r4, #VIRT_OFFSET >> 18//页表项的偏移。

orr r6, r5, r7//物理ram的开如地址。

str r6, [r0]

mov pc, lr

3、调用处理器相关的初始化函数

__arm920_setup:

mov r0, #0

mcr p15, 0, r0, c7, c7  @ invalidate I,D caches on v4

mcr p15, 0, r0, c7, c10, 4  @ drain write buffer on v4

mcr p15, 0, r0, c8, c7  @ invalidate I,D TLBs on v4

//读出cp15的c1寄存器到r0,清除并设置,最终目录如下,使能MMU,禁止内存地址对齐检查功能,使能cache,禁止写入缓存,控制中断向量表的地址为高端。

mrc p15, 0, r0, c1, c0  @ get control register v4

ldr r5, arm920_cr1_clear

bic r0, r0, r5

ldr r5, arm920_cr1_set

orr r0, r0, r5

mov pc, lr

//这里的arm920_cr1_clear=0x3f3f, arm920_cr1_set=0x3135

4、打开MMU

/*

* Setup common bits before finally enabling the MMU.  Essentially

* this is just loading the page table pointer and domain access

* registers.

*/

.type __enable_mmu, %function

__enable_mmu:

#ifdef CONFIG_ALIGNMENT_TRAP

//设置地址对齐检查功能。

orr r0, r0, CR_A

#else

bic r0, r0, #CR_A

#endif

#ifdef CONFIG_CPU_DCACHE_DISABLE

bic r0, r0, #CR_C

#endif

#ifdef CONFIG_CPU_BPREDICT_DISABLE

bic r0, r0, #CR_Z

#endif

#ifdef CONFIG_CPU_ICACHE_DISABLE

bic r0, r0, #CR_I

#endif

//设置MMU中的域

mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \

domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \

domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \

domain_val(DOMAIN_IO, DOMAIN_CLIENT))

mcr p15, 0, r5, c3, c0, 0  @ load domain access register

//把页表基址设置MMU到MMU的C2。

mcr p15, 0, r4, c2, c0, 0  @ load page table pointer

b __turn_mmu_on

/*

* Enable the MMU.  This completely changes the structure of the visible

* memory space.  You will not be able to trace execution through this.

* If you have an enquiry about this, *please* check the linux-arm-kernel

* mailing list archives BEFORE sending another post to the list.

*

*  r0  = cp#15 control register

*  r13 = *virtual* address to jump to upon completion

*

* other registers depend on the function called upon completion

*/

.align 5

.type __turn_mmu_on, %function

__turn_mmu_on:

mov r0, r0

//打开MMU

mcr p15, 0, r0, c1, c0, 0  @ write control reg

mrc p15, 0, r3, c0, c0, 0  @ read id reg

mov r3, r3

mov r3, r3

mov pc, r13

asmlinkage void __init start_kernel(void)

{

char * command_line;

extern struct kernel_param __start___param[], __stop___param[];

/*

* Interrupts are still disabled. Do necessary setups, then

* enable them

*/

lock_kernel();

page_address_init();

printk(KERN_NOTICE);

printk(linux_banner);

//平台相关初始化,SDRAM、CPU。

setup_arch(&command_line);

//smp

setup_per_cpu_areas();

smp_prepare_boot_cpu();

//进程调度队列初始化。

sched_init();

preempt_disable();

//设置每个节点的zonelist。

build_all_zonelists();

//smp

page_alloc_init();

printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);

parse_early_param();

parse_args("Booting kernel", command_line, __start___param,

__stop___param - __start___param,

&unknown_bootoption);

sort_main_extable();

//copy 中断向量表。

trap_init();

rcu_init();

//初始化中断向量表,调用平台中断初始化函数。

init_IRQ();

//进程PID哈希表。

pidhash_init();

//定时器软中断。

init_timers();

//软中断tasklet.

softirq_init();

//初始化时钟中断。

time_init();

//控制台初始化,开始打印。

console_init();

if (panic_later)

panic(panic_later, panic_param);

profile_init();

//打开CPU的中断。

local_irq_enable();

#ifdef CONFIG_BLK_DEV_INITRD

if (initrd_start && !initrd_below_start_ok &&

initrd_start < min_low_pfn << PAGE_SHIFT) {

printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "

"disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);

initrd_start = 0;

}

#endif

//虚拟文件系统数据结构分配。

vfs_caches_init_early();

//把bootmem不用的内存回收到页框分配器。

mem_init();

//slab分配器初化。

kmem_cache_init();

//NUMA

setup_per_cpu_pageset();

numa_policy_init();

if (late_time_init)

late_time_init();

calibrate_delay();

//PID位图初始化。

pidmap_init();

//空

pgtable_cache_init();

prio_tree_init();

anon_vma_init();

#ifdef CONFIG_X86

if (efi_enabled)

efi_enter_virtual_mode();

#endif

//进程创建数据结构初始化。

fork_init(num_physpages);

//多种SLAB分配器的分配。

proc_caches_init();

buffer_init();

unnamed_dev_init();

//空。

key_init();

security_init();

//文件系统相关数据初始化。

vfs_caches_init(num_physpages);

//??

radix_tree_init();

//信号。

signals_init();

/* rootfs populating might need page-writeback */

page_writeback_init();

//PROC文件系统。

#ifdef CONFIG_PROC_FS

proc_root_init();

#endif

cpuset_init();

check_bugs();

acpi_early_init();

//启动INIT进程作剩余部分初始化。

rest_init();

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 刷新view位置,Android View刷新机制实例分析

本文实例讲述了Android View刷新机制。分享给大家供大家参考&#xff0c;具体如下&#xff1a;一、总体说明在Android的布局体系中&#xff0c;父View负责刷新、布局显示子View&#xff1b;而当子View需要刷新时&#xff0c;则是通知父View来完成。二、代码分析1).ViewGroup的a…

android 滚动到底部,Android 控制ScrollView滚动到底部(示例代码)

在开发中&#xff0c;我们经常需要更新列表&#xff0c;并将列表拉倒最底部&#xff0c;比如发表微博&#xff0c;聊天界面等等,这里有两种办法,第一种&#xff0c;使用scrollTo():public static void scrollToBottom(final View scroll, final View inner) {Handler mHandler …

html整体引入js,html页面用js引入js的方式

最原始的是用script便签&#xff1a;1. 使用js打印这个便签&#xff1a;当然这也可以动态引入css以及其他html元素。2. 使用dom的api添加script元素&#xff1a;jQuery中封装了这种方式&#xff0c;并贴心的加入了回调&#xff1a;$.getScript(url,callback(res, status));简单…

vivo android p 机型,vivo X21成全球首批Android P适配机型!vivo :不小心就秀实力了

原标题&#xff1a;vivo X21成全球首批Android P适配机型&#xff01;vivo :不小心就秀实力了近日&#xff0c;2018谷歌I/O大会正式召开&#xff0c;会上发布了大家期待已久的Android P开发者预览版&#xff0c;给我们展示了众多全新特性&#xff0c;其中AI功能的进化让人十分眼…

android继承父类的界面,Android调用父类方法,进行子界面刷新

偶然遇到一个需求、有几个主界面需要获取消息的未读数量由于不是所有类都调用、调用的次数又比较多&#xff0c;整的不上不下的1、对于方法调用次数比较少的 推荐广播广播的方法很方便、但是一堆的消息接收、发送很模式化2、对于较多的方法调用 个人建议直接写共用类中此方法通…

html中依次展开的搜索框,jQuery+CSS3动画展开收缩搜索框特效

js代码function searchToggle(obj, evt){var container $(obj).closest(.search-wrapper);if(!container.hasClass(active)){container.addClass(active);evt.preventDefault();}else if(container.hasClass(active) && $(obj).closest(.input-holder).length 0){con…

直接修改html文本页面没变化,VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析...

本文实例讲述了VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;业务场景我们在使用vue 编写 代码时&#xff0c;我们有一个 多行文本框控件&#xff0c;希望在页面点击一个按钮 在 文本框焦点位置插入一个…

html.partial传递模型,Html.Partial和Html. RenderPartial用法

Html.Partial("MyView")Renders the "MyView" view to an MvcHtmlString.Html.Partial通常呈现的是静态内容&#xff0c;如果不指定的Partial方法中绑定的参数&#xff0c;默认为宿主页面的Model类型&#xff0c;因此如果Partial页面中的Model和主页面的Mo…

live2d内嵌html,博客(网页)添加 Live2D 看板娘

Live2D demoLive2D 看板娘插件 (https://www.fghrsh.net/post/123.html) 的前端 HTML 源码基于 API 加载模型&#xff0c;支持 定制 提示语增加 参数设置 一键定制看板娘&#xff0c;易用性增加 看板娘样式设置&#xff0c;可直接设置宽高度等支持多种一言接口&#xff0c;基于…

计算机启动进入不了桌面图标,电脑开机后不显示桌面图标如何通过修改注册表解决问题...

‍近来有用户发现电脑开机后不显示桌面图标&#xff0c;一般遇到这样的问题&#xff0c;我们会进入任务管理器结束explorer.exe资源管理器进程&#xff0c;再重新启动来解决这个问题。但是&#xff0c;如果这样还无法解决不显示电脑系统桌面图标的问题&#xff0c;那么可以按下…

药学专业报计算机一级有用吗,全网友泣泪劝阻!高考结束之后,什么专业千万不能报?...

原标题&#xff1a;全网友泣泪劝阻&#xff01;高考结束之后&#xff0c;什么专业千万不能报&#xff1f;本文来源&#xff1a;魔都囡啊呀呀呀&#xff0c;高考终于结束啦&#xff0c;大家可以轻松下啦&#xff1f;不过高考的硝烟还没消散&#xff0c;接下来的一个问题就是非常…

如何去掉html body里的 nbsp,html的空格和nbsp怎么去除?

同楼主&#xff0c;这个问题我也碰到了。用html_parser好像不也行replace也不解决不完全&#xff0c;我希望把所有数据(房间类型&#xff0c;面积&#xff0c;位置&#xff0c;详细位置&#xff0c;发布时间&#xff0c;价格)放一行最后没办法只能这样了import requests ##导入…

计算机网络原理04741教学课件,【精编】04741计算机网络原理自考本科2018年4月课件.ppt...

【精编】04741计算机网络原理自考本科2018年4月课件.ppt二、路由选择 5、常用静态路由选择算法的基本内容 6、常见的动态路由选择算法 距离矢量路由算法、链路状态路由算法 7、常用动态路由选择算法的基本内容 8、移动主机的路由选择 9、广播路由选择 10、多播路由选择 第五章 …

计算机数据库管理基本知识,2015年计算机四级考试《数据库技术》基础知识:概念篇...

2015年计算机四级考试《数据库技术》基础知识&#xff1a;概念篇信息与数据1、 信息、物质、能量是组成客观世界并促进社会发展的三大基本要素;2、 信息(Information)--是客观世界事物的存在方式和运动状态的反映&#xff0c;是对事物之间相互联系、相互作用的描述。信息具有可…

coffeescript html5,HTML5——前端预处理技术(Less、Sass、CoffeeScript)

一、Less1.1、概要Less是一种动态样式语言&#xff0c;Less 是一门 CSS 预处理语言&#xff0c;它扩展了 CSS 语言&#xff0c;增加了变量、Mixin、函数等特性&#xff0c;使 CSS 更易维护和扩展。Less 将 CSS 赋予了动态语言的特性&#xff0c;如 变量&#xff0c; 继承&#…

计算机桌面程序名,深度技术win7旗舰版电脑桌面图标只显示名称了怎么办

就算是咱们没有刻意的在桌面创建程序的快捷打开方式&#xff0c;咱们windows系统预装的时候&#xff0c;也会在桌面自行的安装一些快捷方式&#xff0c;例如咱们比较熟悉的回收站、计算机、网络、IE图标等等&#xff0c;而这些图标的显示方式也是系统默认的&#xff0c;由图标和…

计算机专业英语读书报告,英语读书报告怎么写

《英语读书报告怎么写》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《英语读书报告怎么写(8页珍藏版)》请在装配图网上搜索。1、英语读书报告怎么写-工作报告一:英文读书报告撰写格式英文读书报告撰写格式1字体均为Times New Roman报告题目为3号黑体居中学生姓名、专…

《计算机基础知识》读后感300字,计算机应用基础读后感

010在线为您甄选多篇描写计算机应用基础读后感,计算机应用基础读后感精选,计算机应用基础读后感大全&#xff0c;有议论&#xff0c;叙事 &#xff0c;想象等形式。文章字数有400字、600字、800字....缓存时间&#xff1a; 2021-06-21计算机应用基础说课稿随着计算机应用的普及…

一调计算机专业综合理论试卷,一调计算机专业综合理论试卷(盐城)(新编)

一调计算机专业综合理论试卷(盐城)(新编) (15页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;14.9 积分&#xfeff;盐城市2013年普通高校单独招生第一次调研考试计算机应用专业综合理论试卷第I卷(共…

计算机网络聚合怎么设置,交换机的端口聚合如何配置

交换机的端口聚合配置又是怎么回事呢&#xff0c;那么交换机的端口聚合如何配置的呢?下面是学习啦小编收集整理的交换机的端口聚合如何配置&#xff0c;希望对大家有帮助~~交换机的端口聚合配置的方法工具/原料计算机网络工具软件方法/步骤配置交换机Switch0:Switch>enSwit…