Linux系统移植之—uboot移植,你们要的uboot终于来了,堪称精品
作为一名过来人,uboot、kernel对每个学linux的来说都有很深的情谊,因为它们是一个系统跑起来的最基础,每个学linux的都会首先接触到。而它们本身就是一个精美的小系统,里边代码所体现的逻辑、算法以及每个绝妙的C知识点都让你沉醉其中。
uboot 属于bootloader的一种,是用来引导启动内核的,它的最终目的就是,从flash中读出内核,放到内存中,启动内核。具体内容如下:
1 uboot 的介绍及系统结构
1.1 uboot 介绍
1.2 获取 uboot
1.3 uboot 体系结构
1.3.1 uboot 目录结构
2 uboot 的启动过程及工作原理
2.1 启动模式介绍
2.2 阶段 1 介绍
2.2.1 定义入口
2.2.2 设置异常向量
2.2.3 设置 CPU 的模式为 SVC 模式
2.2.4 关闭看门狗
2.2.5 禁掉所有中断
2.2.6 设置以 CPU 的频率
2.2.7 设置 CP15
2.2.8 配置内存区控制寄存器
2.2.9 安装 UBOOT 使的栈空间
2.2.10 BSS 段清 0
2.2.11 搬移 Nand Flash 代码
2.2.12 进入 C 代码部分
2.3 阶段 2 的 C 语言代码部分
2.3.1 调用一系列的初始化函数
2.3.2 初始化网络设备
2.3.3 进入主 UBOOT 命令行
2.4 代码搬运
3 uboot 的移 植过程
3.1 环境
3.2 步骤
3.2.1 修改 Makefile
3.2.2 在 board 子目录中建立 crane2410
3.2.3 在 include/configs/中建立配置头文件
3.2.4 指定交叉编译工具的路径
3.2.5 测试编译能否成功
3.2.6 修改 lowlevel_init.S 文件
2.9 UBOOT 的 Nand Flash 移植
3.2.8 重新编译 uboot
3.2.9 把 uboot 烧入 flash
4.2 常用命令使用说明
4.2.1 askenv(F)
在标准输入(stdin)获得环境变量。
4.2.2 autoscr
从内存(Memory)运行脚本。(注意,从下载地址开始,例如我们的开发板是从 0x30008000 处开始运
行).
CRANE2410 # autoscr 0x30008000
## Executing script at 30008000
4.2.3 base
打印或者设置当前指令与下载地址的地址偏移。
4.2.4 bdinfo
打印开发板信息
CRANE2410 # bdinfo
-arch_number = 0x000000C1 (CPU 体系结构号)
-env_t = 0x00000000 (环境变量)
-boot_params = 0x30000100 (启动引导参数)
-DRAM bank = 0x00000000 (内存区)
--> start = 0x30000000 (SDRAM 起始地址)
--> size = 0x04000000 (SDRAM 大小)
-ethaddr = 01:23:45:67:89:AB (以太网地址)
-ip_addr = 192.168.1.5 (IP 地址)
-baudrate = 115200 bps (波特率)
4.2.5 bootp
通过网络使用 Bootp 或者 TFTP 协议引导境像文件。
CRANE2410 # help bootp
bootp [loadAddress] [bootfilename]
4.2.6 bootelf
默认从 0x30008000 引导 elf 格式的文件(vmlinux)
CRANE2410 # help bootelf
bootelf [address] - load address of ELF image.
4.2.7 bootd(=boot)
引导的默认命令,即运行 U-BOOT 中在“include/configs/smdk2410.h” 中设置的“bootcmd” 中
的命令。如下:
#define CONFIG_BOOTCOMMAND "tftp 0x30008000 uImage; bootm 0x30008000";
在命令下做如下试验:
CRANE2410 # set bootcmd printenv
CRANE2410 # boot
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:abCRANE2410 # bootd
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:ab
4.2.8 tftp(tftpboot)
即将内核镜像文件从 PC 中下载到 SDRAM 的指定地址,然后通过 bootm 来引导内核,前提是所用 PC 要安装设
置 tftp 服务。
下载信息:
CRANE2410 # tftp 0x30008000 zImage
TFTP from server 10.0.0.1; our IP address is 10.0.0.110
Filename 'zImage'.
Load address: 0x30008000
Loading: #################################################################
#################################################################
#################################################
done
Bytes transferred = 913880 (df1d8 hex)
4.2.9 bootm
内核的入口地址开始引导内核。
CRANE2410 # bootm 0x30008000
## Booting image at 30008000 ...
Starting kernel ...
Uncompressing
Linux......................................................................
done, .
4.2.10 go
直接跳转到可执行文件的入口地址,执行可执行文件。
CRANE2410 # go 0x30008000
## Starting application at 0x30008000 ...
4.2.11 cmp
对输入的两段内存地址进行比较。
CRANE2410 # cmp 0x30008000 0x30008040 64
word at 0x30008000 (0xe321f0d3) != word at 0x30008040 (0xc022020c)
Total of 0 words were the same
CRANE2410 # cmp 0x30008000 0x30008000 64
Total of 100 words were the same
4.2.12 coninfo
打印所有控制设备和信息,例如
-List of available devices:
-serial 80000003 SIO stdin stdout stderr
4.2.13 cp
内存拷贝,cp 源地址 目的地址 拷贝大小(字节)
CRANE2410 # help cp
cp [.b, .w, .l] source target count
ANE2410 # cp 0x30008000 0x3000f000 644.2.14 date
获得/设置/重设日期和时间
CRANE2410 # date
Date: 2006-6-6 (Tuesday) Time: 06:06:06
4.2.15 erase(F)
擦除 FLASH MEMORY, 由于该 ARM 板没有 Nor Flash, 所有不支持该命令.
CRANE2410 # help erase
erase start end
- erase FLASH from addr 'start' to addr 'end'
erase start +len
- erase FLASH from addr 'start' to the end of sect w/addr 'start'+'len'-1
erase N:SF[-SL]
- erase sectors SF-SL in FLASH bank # N
erase bank N
- erase FLASH bank # N
erase all
- erase all FLASH banks
4.2.16 flinfo(F)
打印 Nor Flash 信息, 由于该 ARM 板没有 Nor Flash, 所有不支持该命令.
4.2.17 iminfo
打印和校验内核镜像头, 内核的起始地址由 CFG_LOAD_ADDR 指定:
#define CFG_LOAD_ADDR 0x30008000 /* default load address */
该宏在 include/configs/crane2410.h 中定义.
CRANE2410 # iminfo
## Checking Image at 30008000 ...
Image Name: Linux-2.6.14.1
Created: 2006-06-28 7:43:01 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1047080 Bytes = 1022.5 kB
Load Address: 30008000
Entry Point: 30008040
Verifying Checksum ... OK
4.2.18 loadb
从串口下载二进制文件
CRANE2410 # loadb
## Ready for binary (kermit) download to 0x30008000 at 115200 bps...
## Total Size = 0x00000000 = 0 Bytes
## Start Addr = 0x30008000
4.2.19 md
显示指定内存地址中的内容
CRANE2410 # md 0
00000000: ea000012 e59ff014 e59ff014 e59ff014 ................
00000010: e59ff014 e59ff014 e59ff014 e59ff014 ................
00000020: 33f80220 33f80280 33f802e0 33f80340 ..3...3...3@..3
00000030: 33f803a0 33f80400 33f80460 deadbeef ...3...3`..3....
00000040: 33f80000 33f80000 33f9c0b4 33fa019c ...3...3...3...3
00000050: e10f0000 e3c0001f e38000d3 e129f000 ..............).00000060: e3a00453 e3a01000 e5801000 e3e01000 S...............
00000070: e59f0444 e5801000 e59f1440 e59f0440 D.......@...@...
00000080: e5801000 e59f043c e3a01003 e5801000 ....<...........
00000090: eb000051 e24f009c e51f1060 e1500001 Q.....O.`.....P.
000000a0: 0a000007 e51f2068 e51f3068 e0432002 ....h ..h0... C.
000000b0: e0802002 e8b007f8 e8a107f8 e1500002 . ............P.
000000c0: dafffffb e51f008c e2400803 e2400080 ..........@...@.
000000d0: e240d00c e51f0094 e51f1094 e3a02000 ..@.......... ..
000000e0: e5802000 e2800004 e1500001 dafffffb . ........P.....
000000f0: eb000006 e59f13d0 e281f000 e1a00000 ................
4.2.20 mm
顺序显示指定地址往后的内存中的内容,可同时修改,地址自动递增。
CRANE2410 # mm 0x30008000
30008000: e1a00000 ? fffff
30008004: e1a00000 ? eeeeee
30008008: e1a00000 ? q
CRANE2410 # md 30008000
30008000: 000fffff 00eeeeee e1a00000 e1a00000 ................
30008010: e1a00000 e1a00000 e1a00000 e1a00000 ................
30008020: ea000002 016f2818 00000000 000df1d8 .....(o.........
30008030: e1a07001 e3a08000 e10f2000 e3120003 .p....... ......
4.2.21 mtest
简单的 RAM 检测
CRANE2410 # mtest
Pattern FFFFFFFD Writing... Reading...
4.2.22 mw
向内存地址写内容
CRANE2410 # md 30008000
30008000: ffffdffd ffffdffc ffffdffb ffffdffa ................
CRANE2410 # mw 30008000 0 4
CRANE2410 # md 30008000
30008000: 00000000 00000000 00000000 00000000 ................
4.2.23 nm
修改内存地址, 地址不递增
CRANE2410 # nm 30008000
30008000: de4c457f ? 00000000
30008000: 00000000 ? 11111111
30008000: 11111111 ?
4.2.24 printenv
打印环境变量
CRANE2410 # printenv
bootdelay=3
baudrate=115200
ethaddr=01:23:45:67:89:ab
ipaddr=10.0.0.110
serverip=10.0.0.1
netmask=255.255.255.0
stdin=serial
stdout=serialstderr=serial
Environment size: 153/65532 bytes
4.2.25 ping
ping 主机
CRANE2410 # ping 10.0.0.1
host 10.0.0.1 is alive
4.2.26 reset
复位 CPU
4.2.27 run
运行已经定义好的 U-BOOT 的命令
CRANE2410 # set myenv ping 10.0.0.1
CRANE2410 # run myenv
host 10.0.0.1 is alive
4.2.28 saveenv(F)
保存设定的环境变量
4.2.29 setenv
设置环境变量
CRANE2410 # setenv ipaddr 10.0.0.254
CRANE2410 # printenv
ipaddr=10.0.0.254
4.2.30 sleep
命令延时执行时间
CRANE2410 # sleep 1
4.2.31 version
打印 U-BOOT 版本信息
CRANE2410 # version
U-Boot 1.1.4 (Jul 4 2006 - 12:42:27)
4.2.32 nand info
打印 nand flash 信息
CRANE2410 # nand info
Device 0: Samsung K9F1208U0B at 0x4e000000 (64 MB, 16 kB sector)
4.2.33 nand device <n>
显示某个 nand 设备
CRANE2410 # nand device 0
Device 0: Samsung K9F1208U0B at 0x4e000000 (64 MB, 16 kB sector)
... is now current device
4.2.34 nand bad
CRANE2410 # nand bad
Device 0 bad blocks:4.2.35 nand read
nand read InAddr FlAddr size
InAddr: 从 nand flash 中读到内存的起始地址。
FlAddr: nand flash 的起始地址。
size: 从 nand flash 中读取的数据的大小。
CRANE2410 # nand read 0x30008000 0 0x100000
NAND read: device 0 offset 0, size 1048576 ...
1048576 bytes read: OK
4.2.36 nand erease
nand erase FlAddr size
FlAddr: nand flash 的起始地址
size: 从 nand flash 中擦除数据块的大小
CRANE2410 # nand erase 0x100000 0x20000
NAND erase: device 0 offset 1048576, size 131072 ... OK
4.2.37 nand write
nand write InAddr FlAddr size
InAddr: 写到 Nand Flash 中的数据在内存的起始地址
FlAddr: Nand Flash 的起始地址
size: 数据的大小
CRANE2410 # nand write 0x30f00000 0x100000 0x20000
NAND write: device 0 offset 1048576, size 131072 ...
131072 bytes written: OK
4.2.37 nboot
u-boot-1.1.4 代码对于 nboot 命令的帮助不正确,修改如下:
正确的顺序为:
nboot InAddr dev FlAddr
InAddr: 需要装载到的内存的地址。
FlAddr: 在 nand flash 上 uImage 存放的地址
dev: 设备号
需要提前设置环境变量,否则 nboot 不会调用 bootm
CRANE2410 #setenv autostart yes
CRANE2410 # nboot 30008000 0 100000
Loading from device 0: <NULL> at 0x4e000000 (offset 0x100000)
Image Name: Linux-2.6.14.3
Created: 2006-07-06 7:31:52 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 897428 Bytes = 876.4 kB
Load Address: 30008000
Entry Point: 30008040
Automatic boot of image at addr 0x30008000 ...
## Booting image at 30008000 ...
Starting kernel ...
4.3 命令简写说明
所以命令都可以简写,只要命令前面的一部分不会跟其它命令相同,就可以不用写全整个命令.save 命令
CRANE2410 # sa
Saving Environment to Flash...
Un-Protected 1 sectors
Erasing Flash...Erasing sector 10 ... Erased 1 sectors
4.4 把文件写入 NandFlash
如果把一个传到内存中的文件写入到 Nand Flash 中, 如:新的 uboot.bin, zImage(内核),
rootfs 等, 如果做呢?我们可以用 Nand Flash 命令来完成. 但是 Nand Flash 写时,必须先要把 Nand
Flash 的写入区全部擦除后,才能写. 下面以把内存 0x30008000 起长度为 0x20000 的内容写到 Nand
Flash 中的 0x100000 为例.
CRANE2410 # nand erase 0x100000 20000
NAND erase: device 0 offset 1048576, size 131072 ... OK
CRANE2410 # nand write 0x30008000 0x100000 0x20000
NAND write: device 0 offset 1048576, size 131072 ...
131072 bytes written: OK
Kernel,Rootfs,Uboot,INIT进程,内核空间一次讲清楚!!!
linux启动过程
Linux操作系统启动之前,系统硬件需要进行初始化,包括CPU、内存、总线、外设等。当电源被打开后,CPU开始执行复位向量(Reset Vector)中的指令,这个复位向量通常是一个硬件固件中的地址,指向一个固定的内存地址,然后CPU开始从这个地址读取执行指令。通常情况下,CPU在执行复位向量之前需要进行硬件初始化,例如初始化时钟、内存控制器等。当硬件初始化完成后,引导加载程序开始启动。引导加载程序通常是位于系统的非易失性存储器(例如闪存、ROM等)中的一段代码,负责从存储设备(如硬盘、NFS、SD卡等)中读取内核映像文件,将其加载到内存中,并跳转到内核的起始位置开始执行。引导加载程序可以是硬件固件(如BIOS或UEFI),也可以是引导加载器(如GRUB或U-Boot)。内核启动后,它首先会初始化硬件设备,包括CPU、内存、总线、外设等。接下来,内核会初始化文件系统,包括读取根文件系统、安装模块、挂载文件系统等。然后,内核会创建进程并执行用户空间程序,例如init进程,它是所有进程的父进程。此时,用户空间程序开始运行,内核变成了用户空间程序的服务提供者,为用户程序提供系统调用等服务。用户空间程序是指在Linux操作系统中运行的所有应用程序和进程,例如Shell、应用程序、服务进程等。用户空间程序的启动一般由init进程控制。init进程是所有进程的父进程,它负责启动和管理所有其他进程。当内核启动完成后,init进程会通过读取配置文件(如/etc/inittab和/etc/init.d/rc.sysinit)来启动用户空间程序。init进程会根据配置文件中的信息,启动一系列用户空间程序和服务,例如网络服务、系统日志服务、文件共享服务等。在用户空间程序启动后,系统进入了正常工作状态,用户可以通过Shell或其他应用程序来执行各种任务,例如编辑文本、浏览网页、管理文件等。
以全志H6举例
硬件初始化全志H6芯片启动前,需要进行硬件初始化,包括CPU、DDR、EMMC、NAND Flash、SPI Flash、MAC等硬件设备的初始化。这些硬件设备的初始化一般由BootROM和BootROM中的相关代码完成。BootROM是嵌入式系统中的一段代码,它是芯片内置的只读存储器(ROM)中的一段程序,一般由芯片厂商提供。在全志H6芯片中,BootROM是固化在芯片内部的,它是芯片上电后第一时间运行的程序,负责芯片的初始化和引导加载程序的启动。BootROM和Bootloader的关系BootROM是芯片内置的引导程序,负责初始化芯片并启动引导加载程序,而Bootloader是启动流程的下一步,负责从存储设备中读取内核和文件系统等映像文件,并将它们加载到内存中。在嵌入式系统的启动过程中,U-Boot通常是在芯片上电后第二个运行的程序,它负责初始化硬件、读取内核映像文件和文件系统等映像文件,并将它们加载到内存中。最终,U-Boot将系统的控制权转移给内核,由内核进一步初始化和运行系统。引导加载程序启动全志H6芯片启动后,会首先执行BootROM中的代码,读取存储设备(如SD卡或EMMC)中的引导加载程序(如U-Boot),将其加载到DDR内存中。U-Boot是一个开源的引导加载器,它可以在启动时读取SD卡、EMMC、NAND Flash等存储设备中的文件,并将内核和文件系统等映像文件加载到内存中。内核启动U-Boot将内核映像文件(如zImage)加载到内存中后,会调用内核的起始位置开始执行。内核启动后,会完成硬件设备的初始化,包括DDR、NAND Flash、SPI Flash、MAC等硬件设备的初始化,并初始化虚拟内存、进程管理等系统基础设施。然后,内核会挂载文件系统,包括读取根文件系统、安装模块、挂载文件系统等。初始化和运行内核当内核初始化完成后,它会创建第一个用户空间进程(如),并执行用户空间程序。init进程是所有进程的父进程,它负责启动和管理所有其他进程。当内核启动完成后,init进程会根据配置文件(如/etc/inittab和/etc/init.d/rc.sysinit)启动用户空间程序。用户空间程序的启动包括启动一系列系统服务,如网络服务、系统日志服务、文件共享服务等。此时,用户空间程序开始运行,内核变成了用户空间程序的服务提供者,为用户程序提供系统调用等服务。用户空间程序的启动当用户空间程序启动后,系统进入了正常工作状态。在全志H6芯片上,用户可以通过终端(如串口、SSH)或其他应用程序(如浏览器、音视频播放器)来执行各种任务,例如编辑文本、浏览网页、播放音视频等。BootLoader是什么?和Uboot什么关系?
BootLoader是嵌入式系统中非常重要的组件之一,常见的Boot Loader包括以下几种:
U-Boot:是一款开源的Boot Loader,广泛应用于嵌入式系统中。它可以支持多种处理器和架构,提供丰富的命令行接口和配置选项,可以实现内核和设备驱动程序的加载、引导和调试等功能。RedBoot:是另一款常用的开源Boot Loader,也是一个基于命令行的工具。它支持多种处理器和架构,提供了丰富的调试和监控功能,可以实现网络引导和文件系统管理等功能。Das U-Boot:是U-Boot的一个变种,由DENX开发和维护,专门为嵌入式Linux系统设计。它支持多种处理器和架构,提供了丰富的命令行接口和配置选项,可以实现网络引导、文件系统管理和设备树配置等功能。GRUB:是一个广泛应用于PC和服务器系统的Boot Loader。它支持多种操作系统和文件系统,提供了丰富的引导选项和图形用户界面,可以实现多系统引导和启动配置等功能。Bootloader是嵌入式系统启动过程中的一个重要组件,它负责加载内核文件和设备树文件等映像文件,为内核的正常运行提供基础环境。 在加载内核文件和设备树文件时,Bootloader通常需要完成以下几个步骤:
读取内核文件和设备树文件。内核文件是一个镜像文件,包含了操作系统内核的代码和数据,而设备树文件是一个描述硬件设备和系统配置信息的文本文件,通常存储在与内核文件相同的存储设备中。Bootloader需要读取这些文件并将它们加载到内存中,以便后续的操作可以访问和使用它们。解压内核文件。内核文件通常是经过压缩的,需要在加载到内存后进行解压。Bootloader需要根据内核文件的压缩格式进行解压操作,以便内核可以被正确加载和运行。加载设备树文件。设备树文件是一个文本文件,需要经过解析和编译后才能使用。Bootloader需要将设备树文件编译成二进制格式,并将其加载到内存中,以便内核可以访问和使用设备树中描述的硬件设备和系统配置信息。设置内核启动参数。内核启动参数是内核在启动时使用的一组参数,用于指定系统的各种配置和选项。Bootloader需要设置内核启动参数,并将它们传递给内核,以便内核可以按照这些参数进行初始化和配置。转移控制权给内核。最后,Bootloader需要将控制权转移给内核,使得内核可以接管系统的控制权并进行初始化和运行。Bootloader会将内核的入口地址传递给内核,并跳转到内核的入口地址开始执行内核代码。总之,Bootloader在加载内核文件和设备树文件时需要完成多个步骤,包括读取文件、解压文件、编译设备树文件、设置内核启动参数和转移控制权等,以确保内核和系统可以正常启动并运行。
rootfs
在Linux启动时,内核首先被加载到内存中并执行,接着内核需要加载root文件系统(rootfs),以便用户空间进程可以启动并运行。rootfs是文件系统的根,包含了所有的文件和目录,也是其他文件系统的挂载点。rootfs是一个内存文件系统,不依赖于硬盘上的文件系统。它是一个最小化的文件系统,只包含运行Linux所必需的文件和目录,例如/bin、/dev、/etc、/proc、/sys、/tmp和/var等目录。
加载rootfs是Linux启动过程中的一个重要步骤。Linux内核在启动时需要先加载rootfs,以便能够访问文件系统中的内容,例如可执行程序、配置文件等。
为什么kernel(内核)需要加载rootfs,用户空间进程才可以运行?
内核是操作系统的核心部分,负责管理计算机的硬件和软件资源,为用户空间进程提供支持和服务。但是内核本身并不包含用户空间进程,用户空间进程需要通过文件系统来获取执行文件和相关资源。 因此,内核需要加载rootfs(根文件系统)才能让用户空间进程运行。
根文件系统是Linux系统的根目录,它包含了所有系统文件和目录,是用户空间进程的运行环境。当计算机启动时,内核首先加载自身,并初始化硬件设备,然后会尝试挂载根文件系统,使得用户空间进程可以访问其中的文件和资源。
init进程
在Linux系统中,init进程是系统中的第一个用户级进程,它的PID通常为1。init进程的主要作用是负责系统的初始化和启动,它会在系统启动时自动启动,并按照指定的顺序依次启动其他进程和服务,包括加载文件系统、启动守护进程、挂载磁盘分区等。
init进程的启动过程通常可以分为以下几个步骤:
内核初始化。当Linux系统启动时,内核会被加载到内存中,并进行一系列初始化工作,包括初始化CPU、内存管理、设备驱动等。在内核初始化完成后,它会启动init进程作为系统的第一个用户级进程。加载init程序。在内核初始化完成后,init进程会被加载到内存中,并开始执行。init进程的代码通常存储在/sbin/init文件中,它会在启动时被执行。执行初始化脚本。在init进程启动后,它会按照预设的顺序执行初始化脚本,以完成系统的基本配置和启动服务。这些初始化脚本通常存储在/etc/init.d/目录下,它们会在系统启动时被自动执行。启动守护进程。在初始化脚本执行完毕后,init进程会启动一些守护进程,包括syslogd、klogd、crond等。这些守护进程会在后台运行,负责系统的日志记录、定时任务等功能。挂载文件系统。在守护进程启动后,init进程会加载并挂载根文件系统。根文件系统是Linux系统的根目录,所有其他文件系统都必须挂载到根文件系统之下。在挂载文件系统之前,init进程会检查文件系统的完整性,并进行修复和恢复。启动用户登录。最后,init进程会启动一个getty进程,以提供用户登录界面。getty进程会等待用户登录,当用户登录成功后,它会将用户的终端连接到一个shell进程中,从而完成用户登录过程。内核映像文件
内核映像文件(kernel image file)是Linux系统中内核的二进制文件,它包含了内核的所有代码和数据。在Linux系统启动时,内核映像文件被加载到内存中,并开始执行,以完成系统的初始化和启动。
内核映像文件通常存储在文件系统中的/boot目录下,其文件名一般为vmlinuz或bzImage,其中vmlinuz是经过gzip压缩的内核映像文件,而bzImage是经过bzip2压缩的内核映像文件。这些压缩方式可以减小内核映像文件的大小,从而更容易传输和存储。
在Linux系统启动时,内核映像文件被加载到内存中,并进行一系列初始化工作,包括初始化CPU、内存管理、设备驱动等。内核会读取设备树文件,对硬件进行初始化,并加载并挂载根文件系统。 在初始化完成后,内核会启动init进程作为系统的第一个用户级进程,init进程会依次启动其他进程和服务,以完成系统的启动和配置。
内核映像文件的生成通常需要进行编译和链接,其中编译过程需要使用交叉编译器,以将代码编译成适合嵌入式系统的二进制格式。在编译完成后,可以使用一些工具将内核映像文件打包成镜像文件,例如uImage和zImage等,以便于传输和存储。
内核空间和用户态
内核空间和用户态是计算机操作系统中的两个重要概念,它们主要用来区分不同程序的运行环境和访问权限。
内核空间和用户态是两个不同的虚拟地址空间,操作系统内核运行在内核空间,应用程序运行在用户态。内核空间可以直接访问硬件资源和操作系统的所有功能,而用户态程序需要通过系统调用接口来请求内核的帮助。内核空间和用户态之间的切换是通过系统调用、中断、异常等方式实现的。当应用程序需要访问内核资源时,会触发相应的中断或异常,使CPU从用户态切换到内核态。内核空间和用户态之间的切换需要进行一定的上下文切换,包括保存和恢复CPU的状态、切换虚拟地址空间、切换堆栈等操作,因此会带来一定的性能开销。内核空间和用户态的划分是为了保护系统的稳定和安全,内核空间具有更高的访问权限和更大的系统资源,但同时也带来了更高的风险和更大的责任。而用户态程序则更加灵活和易于开发和维护,但其访问权限和系统资源受到一定限制。举个例子
在Linux系统中,用户态程序可以通过系统调用接口请求内核的帮助来访问硬件资源或进行系统操作。例如,一个用户态程序想要读取文件,就可以调用系统调用接口open()和read()来请求内核打开文件并读取数据。在调用系统调用接口时,程序会触发一次从用户态到内核态的上下文切换,使得程序可以访问内核空间中的相关资源和功能。当系统调用结束后,程序再次切换回用户态,继续执行程序的逻辑。这样,用户态程序就可以通过系统调用接口来访问内核资源,而内核则可以保护系统的稳定和安全,防止用户态程序对系统造成损害。
内核模式和用户模式
在计算机系统中,CPU(中央处理器)通常具有两种不同的运行模式,也称为特权级别或权限模式,分别是内核模式(也称为特权模式或系统模式)和用户模式(也称为非特权模式或用户态)。
内核模式 是CPU的一种运行模式,通常是操作系统内核的运行模式。在内核模式下,CPU可以访问和控制所有硬件资源和内存空间,包括处理器、内存、设备等等。内核模式具有更高的权限和特权,可以进行更加底层的操作,例如访问硬件设备、修改内存分页表等等。
用户模式 是CPU的另一种运行模式,通常是用户空间程序的运行模式。在用户模式下,CPU只能访问自己的内存空间和一部分受操作系统授权的硬件资源,无法直接访问操作系统内核和系统资源。用户模式下的程序不能直接执行特权指令,只能通过系统调用等特殊机制来向内核发出请求,从而访问操作系统内核和系统资源。
在实际应用中,操作系统内核通常运行在内核模式下,而用户空间程序则运行在用户模式下。当用户空间程序需要访问操作系统内核和系统资源时,需要通过系统调用等特殊机制来向内核发出请求,从而进入内核模式执行特权操作。这种内核态和用户态的切换,可以保证操作系统的安全性和稳定性。
具体来说,当CPU执行代码时,会根据代码中指令的特权级别来判断当前指令所处的特权级别。如果指令的特权级别等于或高于当前的特权级别,那么CPU会执行这个指令,并且在执行过程中会保持当前的特权级别不变;否则,CPU会抛出异常或者中断,让操作系统处理。
相关问答
嵌入式开发和JAVA开发有什么区别?工作内容有什么不一样?目前在中国从事it行业的人可谓是多不可数,那么作为it男的你又该如何发展?一:IT软件开发眼前道路的选择一份工作在一个人的生活中占据重要地位,对于一个人的...
没有计算机学位证,自己学好编程有用吗?用人单位会要吗?作为一个从事了近10年的软件开发人员,我觉得我是有资格回答这个问题的。1.你说你没有计算机学位证,我不清楚你是什么学历,因为第一学历(本科)决定了你的起点...
会C语言怎么挣钱?熟练掌握计算机视觉和图像处理相关的基本算法及应用;较强的算法实现能力,熟练掌握C/C++编程,熟悉Shell/Python/Matlab至少一种编程语言;在计算机视觉、...
长虹高清网络机顶盒原始密码是多少-ZOL问答刷机,按下UBOOT按钮,然后找到合适的固件,可以解决绝大多数的问题。如果还是不懂可以qq上给你解释说明709853063有用(0)回复数字电视机顶盒的初始PIN码是00...
35岁以上的程序员都去哪里了?在我的朋友圈的IT行业朋友,转换工作角色的很多,转行的不多。最后,我认为不仅仅是程序员,一个想在职场中有所建树的人,都应该从迈入职场就开始自己的职业规...转...