详解Linux内核在arm上的启动过程

系统 Linux
本文详细介绍了Linux内核在arm上的启动过程,一起来看看吧。

 [[426411]]

Linux内核加载过程

通常,Linux内核都是经过gzip加载过之后的映像文件。

  •  bootloader复制压缩内核到内存空间。
  •  内核自解压。
  •  运行内核。

编译完成的Linux内核存放在哪里?

  •  ./vmlinux     elf格式未压缩内核。
  •  arch/arm/boot/compressed/vmlinux    压缩以后的elf格式内核。
  •  arch/arm/boot/zImage    压缩内核。

压缩内核(zImage)的入口

  •  /arch/arm/boot/compressed/vmlinux.lds    该文件为编译器指定link顺序。
  •  ENTRY(_start)    压缩内核从.start段开始执行。
  •  在/arch/arm/boot/compressed/head.S中执行以下爱操作:

        (1)检测系统空间。

        (2)初始化C代码空间。

        (3)跳转到C代码decompress_kernel,

                 arch/arm/boot/compressed/misc.c中。

解压之前的串口输出

  •  include/asm-arm/arch-s3c2410/uncompress.h    中定义了puts作为串口输出函数。
  •  解压结束之后,程序跳转到r5:解压之后内核的起始地址。

开始真正的Linux内核

1、入口在arch/arm/kernel/head-armv.S

2、查找处理器类型

  •  __lookup_processor_type
  •  __lookup_architecture_type

3、初始化页表:__creat_page_tables

4、初始化C代码空间

5、跳转到C代码中,start_kernel

ARM的MMU单元

MMU:内存管理单元

作用:

  •  虚拟地址到物理地址的映射
  •  存储器访问权限
  •  控制Cache

通过MMU的访存

  •  MMU会先查找TLB中的虚拟地址表
  •  如果TLB中没有虚拟地址的入口,硬件从主存储器中的转换表中获取转换与访问权限。

ARM的MMU访存原理

ARM的MMU页表格式

MMU支持基于节或者页的存储器访问。

  •  节:1MB的存储器块
  •  大页:64KB的存储器块
  •  小页:4KB的存储器块
  •  微页:1KB的存储器块

页表的级别

存在主存储器内的转换页表有两个级别:

  •  第一级表:存储节转换表与指向第二级表的指针
  •  第二级表:

        (1)存储大页和小页的转换表。

        (2)存储微页的转换表。

一级页表的地址

第一级表占用空间16KB,必须16KB对齐

第一级描述符

一级表每个入口描述了它所关联的1MB虚拟地址是如何映射的。

节描述符

  •  Bits[1:0] 描述符类型(10b 表示节描述符)
  •  Bits[3:2] 高速缓存(cache)和缓冲位(buffer)
  •  Bits[4] 由具体实现定义
  •  Bits[8:5] 控制的节的16 种域之一
  •  Bits[9] 现在没有使用,应该为零
  •  Bits[11:10] 访问控制(AP)
  •  Bits[19:12] 现在没有使用,应该为零
  •  Bits[31:20] 节基址,形成物理地址的高12 位

节的转换过程

临时内核页表的创建 __create_page_tables 

  1. __create_page_tables:  
  2. pgtbl r4 @ page table address 0x30008000-0x4000  
  3. mov r0, r4 @r0=0x30004000  
  4. mov r3, #0  
  5. add r2, r0, #0x4000  
  6. 1: str r3, [r0], #4  
  7. str r3, [r0], #4  
  8. str r3, [r0], #4  
  9. str r3, [r0], #4  
  10. teq r0, r2  
  11. bne 1b 

把一级页表0x30004000-0xa0080000清空 

  1. krnladr r2, r4 @ start of kernel 

r4=0xa0004000,r2 = 内核起始地址所在1MB对齐空间,0x30000000 

  1. add r3, r8, r2 @ flags + kernel base 

r8 为从处理器信息中得到的MMU 页表标志,r8=0xc0e, r3=0x30000c0e 

  1. str r3, [r4, r2, lsr #18]@ identity mapping 

地址:0x300068000, value:0x30000c0e 

  1. add r0, r4, #(TEXTADDR & 0xff000000) >> 18   
  2. @ start of kernel  
  3. bic r2, r3, #0x00f00000  
  4. str r2, [r0] @ PAGE_OFFSET + 0MB  
  5. add r0, r0, #(TEXTADDR & 0x00f00000) >> 18  
  6. str r3, [r0], #4 @ KERNEL + 0MB  
  7. ...... 

映射表内容

映射结果

进入C代码

init/main.c中的start_kernel函数,进入到了Linux内核代码中。

  •  printk函数
  •  重新初始化页表
  •  初始化中断,trap_init
  •  设置系统定时器、控制台…
  •  创建内核进程init 

 

责任编辑:庞桂玉 来源: 良许Linux
相关推荐

2011-06-28 13:27:13

ARM Linux

2011-09-05 17:35:18

MTK启动过程RTOS

2009-12-03 10:00:46

Linux系统启动

2018-03-13 13:00:03

Linux运维启动分析

2009-08-11 09:03:45

Windows 7系统启动

2018-10-18 14:06:15

Linux系统过程

2011-07-28 10:34:38

Cocoa 程序 启动

2014-06-23 10:31:09

Android启动过程

2021-07-02 06:34:53

Go语言sysmon

2010-07-05 17:38:39

IIS 7.0 FTP

2011-06-29 10:18:20

LINUX QT ARM

2012-02-20 14:47:08

JavaPlay

2012-08-16 09:07:57

Erlang

2010-05-06 14:05:15

Unix系统

2019-05-10 08:00:00

UKUUUbuntuLinux

2020-03-19 08:59:15

SpringMVC启动过程

2009-06-11 10:57:11

netbeans li安装

2010-09-07 14:05:15

Arm移植pppoe

2009-10-16 09:45:41

Linux内核操作系统

2020-04-20 21:30:51

Tomcat部署架构
点赞
收藏

51CTO技术栈公众号