供head.S调用,其中__mmap_switched的b start_kernel跳转到C执行,且永不返回。

跳转到start_kernel时寄存器值:

R0 = cp#15 control register

R1 = machine id

R2 = atags/dtb pointer

R9 = processor ID

stext->__enable_mmu->__turn_mmu_on->ldr pc, __mmap_switched
->__mmap_switched(head-common.S)
->b start_kernel(init/main.c)

http://blog.chinaunix.net/uid-20451980-id-1945242.html

Linux kernel分析(二)
注:本文为Stephen Du原创,转载请注明

这里开始讲解head-common.S的内容。另,我的讲解顺序是按照源码的顺序来进行的而不是按照函数调用的顺序进行,所以读者要注意函数的入口以及返回地址。

这里定义了atag数据的存放地址

14 #define ATAG_CORE 0x54410001

15 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)

这个部分head.S里面开启MMU后执行。此处开始准备执行C代码做准备:主要是text段,初始化数据段的定位!起始kernel本身的段结构跟普通进程大致相同,这也是为什么它被成文宏内核的原因!
 __data_loc是kernel的text段的开始
 __bss_start是__data_loc的结束也是bss段的开始

从上图看得出,kernel必须将text段跟初始化数据段准备好,对于未初始化数据段跟stack段,heap段都是不需要进行准备的!只需要设置stack指针以及heap起始地址就好!因此到了22行后未出现stack跟heap段的定义!

17         .type  
__switch_data, %object

18 __switch_data:

19         .long  
__mmap_switched

20         .long  
__data_loc                  
   @ r4

21         .long  
__data_start                  
 @ r5

22         .long  
__bss_start                  
  @ r6

23         .long   _end
                     
     @ r7
 该内存位置存储了处理器的id,也就是r4寄存器的内容,以防后面的代码丢弃r4的内容

24         .long  
processor_id                  
 @ r4
 该内存位置存储了machine type的信息也是放置r5的内容被丢弃

25         .long  
__machine_arch_type             @ r5
 该内存存储了atag的地址指针,同理防止r6被丢弃了

26         .long  
__atags_pointer                 @ r6

27         .long  
cr_alignment                  
 @ r7
 这个内存位置放置了kernel的stack & heap的内存位置信息以后,只要将pc pointer指向这里就能执行C代码了!

28         .long  
init_thread_union + THREAD_START_SP @ sp

29

此前的代码可能在NOR flash中以XIP方式运行(其实Nand flash也可以XIP,只是有点技术障碍),但是kernel的代码不能总在flash内运行,该函数会进行kernel段的搬移以及处理!

39         .type  
__mmap_switched, %function

40 __mmap_switched:

41         adr    
r3, __switch_data + 4   // r3 point to __mmap_switched本处的注释错误!r3指向__data_loc!

将代码段,初始化数据段以及未初始化的数据段地址分别加载进入r4~r7

43         ldmia   r3!,
{r4, r5, r6, r7}   // load the function's addr into r4~r7;r3 point to
processor_id
 此处比较难以理解,r4=__data_loc是物理上段的存储位置(可能在flash中而不是在RAM中);r5=_data_start是数据在内存的地址,如果二者相等说明已经在RAM中不必做copy,如果不在RAM中则执行copy使之在内存中运行!

44         cmp    
r4, r5                  // Copy
data segment if needed __data_start is the destination and __data_loc is the
src!

copy相关操作

45 1:      cmpne   r5, r6
                 // if
__data_start and __data_loc is not the same start the transfer session

46         ldrne   fp,
[r4], #4

47         strne   fp,
[r5], #4

48         bne     1b

清空未初始化数据段,为执行C代码扫清障碍

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

51 1:      cmp     r6, r7

52         strcc   fp, [r6],#4

53         bcc     1b

执行保存操作。此处最重要的是sp指针的加载!该语句后sp已经指向了kernel的stack上,执行C代码的条件就绪了(代码段ok,初始化数据段ok,未初始化数据段ok,stack
ok)

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

56         str    
r9, [r4]                    
   @ Save processor ID

57         str    
r1, [r5]                    
   @ Save machine type

58         str    
r2, [r6]                    
   @ Save atags pointer

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

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

61              
                     
            @Now we will enter the world of C
code and the MMU is on now!

62         b    
  entry_for_C_call

63         //b    
start_kernel                  
 @For ARM start_kernel is defined in the init/main.c we will never return
from start_kernel at all

144

145 /*

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

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

148  * for the __proc_info lists since we aren't
running with the MMU on

149  * (and therefore, we are not in the correct
address space).  We have to

150  * calculate the offset.

151  *

152  *      r9 = cpuid

153  * Returns:

154  *      r3, r4, r6 corrupted

155  *      r5 = proc_info pointer in
physical address space

156  *      r9 = cpuid (preserved)

157  */

158         .type  
__lookup_processor_type, %function

159 __lookup_processor_type:

160         adr     r3, 3f

161         ldmda   r3, {r5 -
r7}

162         sub     r3, r3,
r7                    
 @ get offset between virt&phys

163         add     r5, r5,
r3                    
 @ convert virt addresses to

164         add     r6, r6,
r3                    
 @ physical address space

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

166         and     r4, r4,
r9                    
 @ mask wanted bits

167         teq     r3, r4

168         beq     2f

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

170         cmp     r5, r6

171         blo     1b

172         mov     r5, #0
                     
   @ unknown processor

173 2:      mov     pc, lr

174

175 /*

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

177  */

178 ENTRY(lookup_processor_type)

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

180         mov     r9, r0

181         bl    
 __lookup_processor_type

182         mov     r0, r5

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

184

185 /*

186  * Look in and arch/arm/kernel/arch.[ch]
for

187  * more information about the __proc_info and
__arch_info structures.

188  */

189         .long  
__proc_info_begin

190         .long  
__proc_info_end

191 3:      .long   .

192         .long  
__arch_info_begin

193         .long  
__arch_info_end

194

195 /*

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

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

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

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

200  *

201  *  r1 = machine architecture number

202  * Returns:

203  *  r3, r4, r6 corrupted

204  *  r5 = mach_info pointer in physical
address space

205  */

206         .type  
__lookup_machine_type, %function

207 __lookup_machine_type:

208         adr     r3, 3b

209         ldmia   r3, {r4, r5,
r6}

210         sub     r3, r3,
r4                    
 @ get offset between virt&phys

211         add     r5, r5,
r3                    
 @ convert virt addresses to

212         add     r6, r6,
r3                    
 @ physical address space

213 1:      ldr     r3, [r5,
#MACHINFO_TYPE]        @ get machine type

214         teq     r3, r1
                     
   @ matches loader number?

215         beq     2f
                     
       @ found

216         add     r5, r5,
#SIZEOF_MACHINE_DESC    @ next machine_desc

217         cmp     r5, r6

218         blo     1b

219         mov     r5, #0
                     
   @ unknown machine

220 2:      mov     pc, lr

221

222 /*

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

224  */

225 ENTRY(lookup_machine_type)

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

227         mov     r1, r0

228         bl    
 __lookup_machine_type

229         mov     r0, r5

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

231

232 /* Determine validity of the r2 atags pointer.
 The heuristic requires

233  * that the pointer be aligned, in the first 16k
of physical RAM and

234  * that the ATAG_CORE marker is first and
present.  Future revisions

235  * of this function may be more lenient with the
physical address and

236  * may also be able to move the ATAGS block if
necessary.

237  *

238  * r8  = machinfo

239  *

240  * Returns:

241  *  r2 either valid atags pointer, or zero

242  *  r5, r6 corrupted

243  */

244

245         .type   __vet_atags,
%function

246 __vet_atags:

247         tst     r2,
#0x3                    
   @ aligned?

248         bne     1f

249

250         ldr     r5,
[r2, #0]                    @
is first tag ATAG_CORE?

251         subs    r5, r5,
#ATAG_CORE_SIZE

252         bne     1f

253         ldr     r5,
[r2, #4]

254         ldr     r6,
=ATAG_CORE

255         cmp     r5, r6

256         bne     1f

257

258         mov     pc, lr
                     
   @ atag pointer is ok

259

260 1:      mov     r2, #0

261         mov     pc, lr

linux head-common.s分析(转)的更多相关文章

  1. linux系统web日志分析脚本

    linux系统web日志分析这方面工具比较多,比如logwatch或awstats等使用perl语言开发,功能都非常强大.但这些软件都需要进行一些配置,很多朋友往往在技术方面没有投入太多力量,即便参照 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第八周作业

    <Linux内核原理与分析>第八周作业 一.本周内容概述: 理解编译链接的过程和ELF可执行文件格式 编程练习动态链接库的两种使用方式 使用gdb跟踪分析一个execve系统调用内核处理函 ...

  3. Android/Linux下CGroup框架分析及其使用

    1 cgroup介绍 CGroup是control group的简称,它为Linux kernel提供一种任务聚集和划分的机制,可以限制.记录.隔离进程组(process groups)所使用的资源( ...

  4. Linux Kernel Oops异常分析

    1.PowerPC小系统内核异常分析 1.1  异常打印 Unable to handle kernel paging request for data at address 0x36fef31eFa ...

  5. 20169212《Linux内核原理与分析》课程总结

    20169212<Linux内核原理与分析>课程总结 每周作业链接汇总 第一周作业:完成linux基础入门实验,了解一些基础的命令操作. 第二周作业:学习MOOC课程--计算机是如何工作的 ...

  6. 1.linux服务器的性能分析与优化

    [教程主题]:1.linux服务器的性能分析与优化 [课程录制]: 创E [主要内容] [1]影响Linux服务器性能的因素 操作系统级 CPU 目前大部分CPU在同一时间只能运行一个线程,超线程的处 ...

  7. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  8. Linux系统日志及日志分析

    Linux系统日志及日志分析   Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息. 大部分Linux发行版默认的日志守护进程为 syslog,位 ...

  9. 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化

    高性能Linux服务器 第10章    基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...

  10. Linux内核源代码情景分析系列

    http://blog.sina.com.cn/s/blog_6b94d5680101vfqv.html Linux内核源代码情景分析---第五章 文件系统  5.1 概述 构成一个操作系统最重要的就 ...

随机推荐

  1. luogu P2828 Switching on the Lights(开关灯)

    题目背景 来源:usaco-2015-dec Farm John 最近新建了一批巨大的牛棚.这些牛棚构成了一个N*N的矩形网络.(1<n<100) 然而bessie十分怕黑,他想计算可以把 ...

  2. nginx配置及常见问题

    问题 1.openresty请求时,不能解析域名? openresty依赖配置里面的resolver 192.168.1.1; 2.文件上传是报错413 Request Entity Too Larg ...

  3. 【安居客】资深PHP软件开发工程师

    工作职责: 1.网站项目的开发和维护: 2.负责技术部软件开发架构设计: 3.负责生产环境.测试环境和生产环境服务器运维和优化: 4.负责研究较前沿和复杂的技术运用: 岗位要求: 1.熟悉 PHP 程 ...

  4. ios学习流水账1

    1.UIImageview设边框.圆角 需要引QuartzCore/QuartzCore.h> //设UIImageView边框 CALayer *layer = [m_imgView laye ...

  5. JAVA常见算法题(十九)

    package com.xiaowu.demo; /** * * 有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13...求出这个数列的前20项之和. * * * @author WQ ...

  6. sqlserver中常用的四个选项(NOCOUNT/ANSI_NULLS/QUOTED_IDENTIFIER/ XACT_ABORT)

    1 NOCOUNT选项 当 SET NOCOUNT 为 ON 时,不返回计数.当 SET NOCOUNT 为 OFF 时,返回计数. eg: if object_id(N'table_test',N' ...

  7. JS创建对象的方式有几种

    相信但凡作为一个前端工程师,都被面试到过这个面试题目,HR考察的就是对oop思想的理解. 作为一个从后端转过来的怂逼,oop一直是心中的永远的痛啊. 这几天一直在通读js高级程序设计,重复理解js创建 ...

  8. 使用springMVC上传文件

    control层实现功能: @RequestMapping(value="upload2") public String upLoad2(HttpServletRequest re ...

  9. 【Java】String和Date、Timestamp之间的转换

    首先,定义一个Format的日期格式: SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 一.S ...

  10. android SQLite(单词的添加与查询应用)

    本人小白,刚接触android,为方便记忆,将平时练习的代码写下来,跟大家分享,也希望大神批评指正. 这个实例主要用到的SQLite数据库的操作,可以向数据库添加单词,查询,修改以及删除单词,描述如有 ...