day45-系统移植内核

day45-系统移植内核

一、内核简介

Linux内核是Linux操作系统的核心部分,负责处理系统的主要操作,如硬件抽象、进程调度、内存管理,以及提供一个稳定、安全的环境来运行应用程序。从技术上来看,内核其实是硬件和软件之间的连接层,我们也可以称之为中间层。

1.1 内核实现策略

  • 宏内核
    内核的所有代码,包括子系统(如内存管理、文件管理、设备驱动程序)都打包到一个文件中。内核中的每一个函数都可以访问到内核中所有其他部分。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的

  • 微内核
    最基本的功能由中央内核(微内核)实现。所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信。

1.2 内核的核心模块

1.2.1 进程的管理

Linux操作系统中的进程管理是内核的核心功能之一。以下是一些关键的概念和特性:

进程与线程
  • 进程:被视为执行环境的实例,包括程序代码、相关的数据、寄存器的状态、程序计数器、堆和栈等。
  • 线程:进程中的一个执行单元,共享进程的资源,有自己独立的执行序列。Linux内核通过轻量级进程(LWP)实现线程。
进程状态

进程可能处于以下状态之一:

  • 运行(正在CPU上执行或准备好运行但在等待CPU变得可用)
  • 等待/睡眠(等待某些条件成立或等待资源可用)
  • 停止(例如,当收到SIGSTOP信号或者正在被调试)
  • 僵尸(进程已经终止,但父进程还没有收集到它的终止状态)
进程调度

内核的调度器负责决定哪个进程应该获得CPU的使用权。Linux使用优先级和调度策略来决定进程的执行顺序。

以下是Linux进程调度的一些重要概念:

(1)调度器和调度策略:

Linux内核中有一个调度器组件,负责管理和调度所有的进程。调度器根据一定的策略来决定下一个要运行的进程。

Linux支持多种调度策略,包括:

SCHED_FIFO:实时调度策略,先进先出。对于具有相同优先级的进程,最早到达的进程首先获得处理器,一直运行直到自愿放弃或者更高优先级的进程就绪。

SCHED_RR:实时调度策略,循环执行。这是一种为具有相同优先级的进程设计的公平策略,当一个进程耗尽了它的时间片,调度器将选择下一个进程执行。

SCHED_OTHER:普通的非实时调度策略,这是默认的调度策略,采用的是CFS(Completely Fair Scheduler)调度算法。

(2)优先级:

Linux的每个进程都有一个相关联的优先级,决定了它在和其他进程竞争CPU时的地位。实时进程有静态优先级范围,普通进程有动态优先级范围。实时进程的优先级总是高于普通进程。

(3)时间片:

在Linux系统中,每个进程被赋予一个时间片,即进程可以运行的时间长度。时间片用完后,进程将被调度出CPU,然后调度器选择另一个进程运行。

(4)上下文切换:

当调度器决定替换当前正在运行的进程时,它执行一个被称为”上下文切换”的操作。这包括保存当前进程的状态,然后加载新进程的状态。这是一个开销相对较大的操作,因为它涉及到CPU寄存器和内存映射等状态信息的保存和加载。

进程创建与结束

进程通过系统调用fork()创建。进程结束通常是因为它完成了其工作或者因为收到一个终止信号。

进程间通信

Linux提供了多种进程间通信(IPC)机制,包括管道、信号、消息队列、共享内存、信号量等。

用户和权限

每个进程都有一个相关联的用户ID,用于确定它的权限。


1.2.2 内存管理

Linux内存管理是一个非常重要的部分,涉及到多个关键的概念和组件。

物理与虚拟内存
  • 物理内存:指的是实际的RAM。
  • 虚拟内存:它允许计算机看似拥有比实际更多的RAM,通过使用硬盘空间作为额外的内存。
分页和分段
  • 分页:操作系统将虚拟内存划分为大小固定的块,称为页面。物理内存也被划分为大小固定的块,称为页帧。
  • 分段:是将内存划分为大小可变的块。
页面置换算法
  • 当所有的物理内存都被使用时,操作系统需要决定哪些页面应被移出内存,为新的页面腾出空间。这个决定是由页面置换算法(page replacement algorithm)来做的。
内存分配
  • 静态内存分配:在程序编译时由编译器自动完成。
  • 自动内存分配(栈内存分配):在程序运行时由编译器自动完成。
  • 动态内存分配(堆内存分配):由程序员显式调用malloc,calloc等函数完成。
内存映射
  • 内存映射(Memory Mapping)是一种能让程序直接访问物理内存的方法。
Swap空间
  • Swap空间是硬盘上的一块区域,被操作系统用作虚拟内存。当物理内存不足时,操作系统可以将一部分数据(页面)移出物理内存,存放到Swap空间,从而释放出物理内存供其他用途使用。

1.2.3 文件系统

文件系统类型

Linux支持多种文件系统类型,包括但不限于以下几种:

  • ext2/ext3/ext4:Linux的传统文件系统,ext4是最新版本,提供了许多改进和新功能。
  • XFS:一种高性能的日志文件系统,适合处理大文件和大存储设备。
  • Btrfs:一个现代的、具有许多高级功能的文件系统,如检查点、快照和动态空间分配。
  • FAT32/NTFS:由Microsoft开发,主要在Windows系统中使用,但Linux也提供了对它们的支持。
文件系统层次结构

Linux文件系统遵循一种统一的目录结构,所有内容都从根目录/开始。以下是一些重要的目录:

  • **/**:根目录,所有的文件和目录都从这里开始。
  • /home:用户的主目录,每个用户在这里都有一个自己的目录。
  • /etc:系统配置文件的存储位置。
  • /var:经常变化的文件,如日志文件和邮件队列等。
  • /bin/sbin:二进制可执行文件的存储位置,如常用的命令和系统程序。
  • /lib:库文件的存储位置。
inode

每个文件都有一个相关的inode,它存储了文件的元数据,如文件大小、创建时间、修改时间、所有者和权限等。inode号是文件在文件系统中的唯一标识。

硬链接和软链接

Linux支持两种类型的文件链接:

  • 硬链接:指向文件的inode的直接引用。所有的硬链接都指向同一个inode,因此看起来就像是同一个文件。
  • 软链接(符号链接):指向文件路径的引用,类似于Windows中的快捷方式。
挂载和卸载

在Linux中,设备(如硬盘分区或USB驱动器)必须先挂载到文件系统的某个点(称为挂载点),然后才能访问其中的文件。同样,设备可以从文件系统卸载,此后就无法访问其内容。


1.2.4 设备驱动

设备驱动是一段可以让操作系统和硬件设备进行交互的程序。下面是一些关于Linux设备驱动的主要概念:

设备驱动的类型

Linux中的设备驱动主要可以分为以下三种类型:

  • 字符设备驱动:用于控制字符设备,这些设备以字符为单位进行数据传输,例如键盘和鼠标。
  • 块设备驱动:用于控制块设备,这些设备以数据块为单位进行数据传输,例如硬盘和光驱。
  • 网络设备驱动:用于控制网络设备,例如网络适配器和路由器。
加载和卸载设备驱动

在Linux中,设备驱动可以动态地加载和卸载。可以使用insmod命令来加载设备驱动,使用rmmod命令来卸载设备驱动。

设备文件

Linux将所有的设备视为文件,设备文件通常位于/dev目录中。设备文件可以是字符设备文件或块设备文件,可以通过读写这些设备文件来控制硬件设备。

udev

udev是Linux 2.6内核和更高版本的一个设备管理工具,它可以动态地创建和管理设备节点,使设备管理更加灵活。

驱动模块

驱动模块是包含设备驱动函数的程序,它们可以在运行时动态地加载和卸载。这使得Linux内核可以保持小型和高效,同时也能支持大量不同类型的硬件设备。

编写设备驱动

编写设备驱动是一个复杂的任务,需要深入理解硬件设备的工作原理以及Linux内核的工作机制。驱动程序需要在内核空间运行,因此它们必须遵循特定的编程规则和约定。


1.2.5 网络栈

Linux网络栈是一个实现了TCP/IP网络协议的软件栈。以下是一些重要的概念:

网络模型

TCP/IP模型由四层构成:应用层、传输层、网络层和链路层。每一层都负责处理特定的任务,并为上一层提供服务。

协议

网络栈包括一组协议,这些协议定义了数据在网络中的传输方式。其中最重要的两个协议是TCP(传输控制协议)和IP(互联网协议)。

Socket编程

Socket API用于创建和管理网络连接。通过socket,应用程序可以发送和接收数据。

网络设备

网络设备是用于发送和接收数据包的硬件设备。在Linux中,每个网络设备都由一个设备驱动程序来管理。

路由

路由是决定数据包从源地址到目的地址所走的路径的过程。路由表是用于存储路由信息的数据结构。

网络安全

网络安全包括一系列用于保护网络连接和数据的技术。其中包括防火墙(用于阻止未授权的网络访问)和IPSec(一种用于加密IP数据包的协议)。

网络调试工具

Linux提供了多种用于调试网络问题的工具,如ping(用于测试网络连通性),traceroute(用于跟踪数据包的路由路径),netstat(用于显示网络状态)等等。




二、内核移植

  1. 准备内核源代码
  2. makefile编辑交叉编译环境
  3. make exynos_defconfig默认配置,配置文件放在 arch/arm/configs下
  4. make menuconfig图形界面配置内核
  5. make uImage编译内核
  6. make dtbs编译设备树
  7. 按照需求在设备树中添加设备和配置内核,再重新编译
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
内核移植:

一、 内核准备:

1. 内核源代码准备
1)官网下载Linux内核源代码
2)找供应商要(得到Linux内核源代码:linux-3.14.tar.xz)

2. 拷贝源代码到工作目录:
cp linux-3.14.tar.xz
3. 进入Linux内核源代码所在目录,解压Linux内核源代码
cd
tar xf linux-3.14.tar.xz
4. 进入到源代码目录中
cd linux-3.14

二、 内核编译:
5. 修改编译平台和交叉编译环境
进入Makefile文件,修改参数:
修改:
199 ARCH ?= $(SUBARCH)
200 CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
为:
199 ARCH ?= arm
200 CROSS_COMPILE ?= arm-none-linux-gnueabi-

6. 导入默认配置,配置文件放在 arch/arm/configs下
make exynos_defconfig
7. 配置内核
make menuconfig
正常执行,会弹出一个菜单选项,我们可以去选择需要配置的内核;
注意:
(如果在编译的时候出现了下面的错误,则说明图形界面库没有安装,需要安装库
sudo apt-get install exuberant-ctags
sudo apt-get install libncurses5-dev
)
*** Unable to find the ncurses libraries or the
*** required header files.
*** 'make menuconfig' requires the ncurses libraries.
***
*** Install ncurses (ncurses-devel) and try again.
***
make[1]: *** [scripts/kconfig/dochecklxdialog] Error 1
make: *** [menuconfig] Error 2
第二种:
farsight@ubuntu:~/fs4412/1905/linux-3.14$ make menuconfig
scripts/kconfig/mconf Kconfig
Your display is too small to run Menuconfig!
It must be at least 19 lines by 80 columns.
make[1]: *** [menuconfig] Error 1
make: *** [menuconfig] Error 2

表示终端太小,全屏显示就可以解决

正常执行菜单选项,选择串口信息:
/* 将串口选择为 2 */
System Type --->
(2) S3C UART to use for low-level messages

8. 编译内核
make uImage
编译成功会生成一个经过压缩后的镜像文件uImage,其生成的文件路径为:arch/arm/boot/uImage
注意:(如果在编译的时候出现了下面的错误,则说明缺少mkimage工具,
需将第一天工具中的mkimage拷贝到ubuntu的/usr/bin目录下)
"mkimage" command not found - U-Boot images will not be built
make[1]: *** [arch/arm/boot/uImage] Error 1
make: *** [uImage] Error 2

三、设备树编译:
9. 修改设备树文件
参考板origen的设备数文件为参考:
cp arch/arm/boot/dts/exynos4412-origen.dts arch/arm/boot/dts/exynos4412-fs4412.dts
10. 修改Makefile,添加编译项:
vim arch/arm/boot/dts/Makefile

exynos4412-origen.dtb \
下添加如下内容
exynos4412-fs4412.dtb \
11. 编译设备树文件:
make dtbs

12. 拷贝编译的内核和设备树到tftp共享文件中
cp arch/arm/boot/uImage /tftpboot
cp arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot

四、调试内核和设备树;
采用tftp下载内核和设备树,nfs挂载根文件系统
set tftp 41000000 uImage\; tftp 42000000 exynos4412-fs4412.dtb\; bootm 41000000 - 42000000
set bootargs root=/dev/nfs nfsroot=192.168.9.120:/source/nfs/rootfs rw clk_ignore_unused console=ttySAC2,115200 init=/linuxrc ip=192.168.9.233
saveenv
掉电重启板子 //会看到内核信息输出。 但后面有报错,正常 (因为网卡等还没移植,nfs挂载肯定失败)


【网卡驱动的移植】
1. 修改设备树文件

添加:linux-3.14/arch/arm/boot/dts/exynos4412-fs4412.dts
srom-cs1@5000000 {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x5000000 0x1000000>;
ranges;

ethernet@5000000 {
compatible = "davicom,dm9000";
reg = <0x5000000 0x2 0x5000004 0x2>;
interrupt-parent = <&gpx0>;
interrupts = <6 4>;
davicom,no-eeprom;
mac-address = [00 0a 2d a6 55 a2];
};
};

添加设备编译参数
make menuconfig
[*] Networking support ---> //配置支持TCP/IP
Networking options --->
<*> Packet socket
<*>Unix domain sockets
[*] TCP/IP networking
[*] IP: kernel level autoconfiguration
Device Drivers ---> //配置支持DM9000网卡驱动
[*] Network device support --->
[*] Ethernet driver support (NEW) --->
<*> DM9000 support
File systems ---> //配置支持网络文件系统NFS
[*] Network File Systems (NEW) --->
<*> NFS client support
[*] NFS client support for NFS version 2
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] Root file system on NFS


重新编译内核和设备树
make uImage
make dtbs
将编译好的内核和设备树拷贝到tftp共享目录中
cp arch/arm/boot/uImage /tftpboot
cp arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot
采用tftp下载内核和设备树,nfs挂载根文件系统
set tftp 41000000 uImage\; tftp 42000000 exynos4412-fs4412.dtb\; bootm 41000000 - 42000000
set bootargs root=/dev/nfs nfsroot=192.168.1.190:/source/nfs/rootfs rw clk_ignore_unused console=ttySAC2,115200 init=/linuxrc ip=192.168.1.191

如果挂载失败:修改文件drivers/clk/clk.c
修改static bool clk_ignore_unused; 为:static bool clk_ignore_unused = true; //忽略时钟
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信