第二章:你的第一次嵌入式体验
本章包含以下子章节:
- 是否选择嵌入式系统?
- 嵌入式系统剖析
- 存储考虑
- 嵌入式Linux发行版
- 本章小结
- 2.1 是否选择嵌入式系统?
- 包含一个处理引擎,例如通用微处理器
- 通常为专用的应用程序或目的而设计
- 包含一个简单的用户界面(也可以没有),例如汽车发动机点火控制器
- 一般都配置很有限的系统资源,比如很小的内存或者没有硬盘
- 可能有电源限制,比如系统是由电池供电
- 通常不作为通用计算机平台
- 通常预装好应用程序,而不是由用户选择
- 上市之前已经集成好所有的硬件和软件模块
- 应用程序自动执行,一般无需人工干预
- 包含一个处理引擎,例如通用微处理器
- 2.2 嵌入式系统剖析
- 2.2.1 典型的嵌入式Linux开发环境
- 2.2.2 开始目标板的工作
U-Boot 1.1.4 (Mar 18 2006 - 20:36:11)
AMCC PowerPC 440EP Rev. B
Board: Yosemite - AMCC PPC440EP Evaluation Board
VCO: 1066 MHz
CPU: 533 MHz
PLB: 133 MHz
OPB: 66 MHz
EPB: 66 MHz
PCI: 66 MHz
I2C: ready
DRAM: 256 MB
FLASH: 64 MB
PCI: Bus Dev VenId DevId Class Int
In: serial
Out: serial
Err: serial
Net: ppc_4xx_eth0, ppc_4xx_eth1
=>
“优山美地”加电后,U-Boot程序执行低级的硬件初始化,其中就包括了配置串口,并打印出了一行信息(参考清单2-1):U-Boot 1.1.4 (Mar 18 2006 - 20:36:11),紧接着是打印出处理器的名称和版本信息,再然后是版型信息。这些信息只是该开发板的通用信息,是在U-Boot源代码中由开发人员硬编码进去的字符串。(译者注:要想打印这些信息,U-Boot要支持该目标板,可以是U-Boot官方本身的支持,也可以是第三方的支持)下面的信息则是针对该目标板特有的一些信息:包括内部时钟的配置(注意,要在串口输出任何信息之前配置好时钟,否则串口无法正常工作),完成后,U-Boot程序根据各硬件子系统的静态配置逐个配下去并对配置结果信息进行打印。这里我们可以看到I2C总线,DRAM,FLASH,PCI总线和网络子系统的配置结果信息。最后,U-Boot停在命令提示符“=>”,等待用户通过串口输入命令。
- 2.2.3 启动Linux kernel
=> tftpboot 200000 uImage-440ep
ENET Speed is 100 Mbps - FULL duplex connection
Using ppc_4xx_eth0 device
TFTP from server 192.168.1.10; our IP address is 192.168.1.139
Filename 'uImage-amcc'.
Load address: 0x200000
Loading: ####################################################
######################################
done
Bytes transferred = 962773 (eb0d5 hex)
=> bootm 200000
## Booting image at 00200000 ...
Image Name: Linux-2.6.13
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 962709 Bytes = 940.1 kB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Linux version 2.6.13 (chris@junior) (gcc version 4.0.0 (DENX ELDK 4.0 4.0.0))
#2 Thu Feb 16 19:30:13 EST 2006
AMCC PowerPC 440EP Yosemite Platform
...
< Lots of Linux kernel boot messages, removed for clarity >
...
amcc login: <<< This is a Linux kernel console command prompt
tftpboot命令告诉U-Boot通过tftp协议(注2)从远端网络中把kernel image uImage-440ep拷贝到内存的0x200000地址处,在本例中,kernel image放置在开发工作站中(通常是用开发主机当工作站),tftpboot命令传递了的地址是目标板内存中加载kernel image的物理地址。现在可以不用了解太多U-Boot的细节,后面我们有专门的一章介绍:第七章 Bootloaders
- 注2:tftp服务器以及其他一些服务器的配置我们会在第十二章中讲:第十二章 嵌入式开发环境
注意bootm命令执行完后就意味着U-Boot完成了使命,结束了生命周期,这是一个很重要的概念,这一点和台式电脑的BIOS有很大不同,大部分嵌入式系统都是按照这种架构设计,当Linux kernel开始启动时,bootloader程序就已经完成退出了。Linux kernel会把先前bootloader占用的内存和系统资源全部回收并重新使用,只有重启系统才你能再次执行bootloader。
最后,还有一点值得注意。清单2-2列出的串口输出信息中,从第一行到
Uncompressing Kernel Image ... OK
这一行(包含这一行),都是U-Boot程序的输出,剩下的启动信息则是由Linux kernel打印的,这一行刚好是U-Boot退出、Linux kernel开始执行的分界线,后面的章节我们还会详细介绍。- 2.2.4 Kernel初始化概览
...
Looking up port of RPC 100003/2 on 192.168.0.9
Looking up port of RPC 100005/1 on 192.168.0.9
VFS: Mounted root (nfs filesystem).
Freeing init memory: 232K
INIT: version 2.78 booting
...
coyote login:
在我们的串口终端上,进入到登录提示符之前,系统先执行挂载root文件系统(rootfs)的操作,在清单2-3中,Linux系统通过以太网将一台IP地址是192.168.0.9的NFS服务器(注3)挂载到本地,通常,这台服务器就是你的开发工作站,挂载到本地的目录中(也就是rootfs中)包含在开发工作站上交叉编译出来的应用程序,以及其他一些系统库,实用程序等,从而构成一个完整的GNU/Linux系统。- 注3:我们将在第十二章讲解NFS服务器和其他所需的服务器
Linux还可以从其他设备挂载root文件系统,最常见的就是将硬盘的某个分区挂载成root文件系统(译者注:事实上很多嵌入式设备并没有硬盘,那么这里讲的也可以扩展为将本地存储介质,如Nand Flash的某个分区挂载成root文件系统),事实上读者的台式电脑上运行的Linux就是这么做的。尽管当目标板远离开发主机所在的网络环境时NFS就不可用了,但是对于开发人员来讲,通过NFS挂载文件系统的方式会更加强大和灵活,后面章节的叙述读者会更加深刻地体会到这一点。
- 2.2.5 第一个用户空间进程:init
在进行下面的学习之前,我们先看清单2-3中的这一行信息:
INIT: version 2.78 booting.
系统运行到上面这行文字之前,kernel本身都在执行代码,在“kernel上下文环境”中执行一步步的初始化操作,这个过程中,kernel拥有所有的系统内存,对所有的系统资源都全权管控,并且可以访问所有的物理内存和I/O子系统。(译者注:这个阶段,系统所有的软硬件资源都由kernel直接管理)
当Linux kernel执行完内部的初始化,并已挂载root文件系统后,默认会开启一个用户程序:init,kernel开启init进程后就切换到用户空间了。在这种操作模式下,用户空间进程只会访问受限的系统资源,如果用户空间的进程需要使用kernel提供的服务,例如设备和文件的I/O操作,必须通过系统调用实现。相对于kernel直接访问物理内存,用户空间的进程或程序运行在一块虚拟内存空间中,这块内存由kernel随机分配(注4)和管理。在处理器中专门的内存管理模块的支持下,kernel为用户空间进程维护了虚拟内存到物理内存的地址转换。这种架构最大的好处就在于,单一进程出错不会影响到其他进程的内存空间。而一些旧的嵌入式系统不具备这样的内存管理架构的话,就会存在致命的缺陷,一旦出现内存管理的bug几乎很难定位。
- 注4:事实上并不是随机分配,我们权且先这样认为,后续章节我们再深入讨论。
不要被这些陌生的概念吓倒,本章节只是为了让读者在深入学习本书之前先对嵌入式系统有个宏观上的了解,后续章节会逐个对其进行深入介绍。