基础概念总结
掌握Linux常用的基本命令功能、语法结构,用法等。
具体命令参考实验指导书、相关PPT等资料内容。
什么是操作系统(OS)?
操作系统是用以控制和管理计算机系统资源,方便用户使用的程序和数据结构的集合。在所有的系统软件中,操作系统是一种首要的、最基本、最重要的系统程序,也是最庞大、最复杂的系统软件。
现代操作系统类型
1 分时系统
基本特征:(1)多路性 ( 2)独立性 (3)交互性 (4)及时性
2 实时操作系统
能在限定的时间内对输入进行快速处理并作出响应的计算机处理系统。
3 微机操作系统
4. 多处理机、分布式和网络操作系统
分布式操作系统:分布式系统具有一个统一的操作系统,它可以把一个大任务划分成很多可以并行执行的子任务,并按一定的策略将它们动态地分配给各个计算机执行,并控制管理各个计算机的资源分配、运行及计算机之间的通信,以协调任务的并行执行。
网络操作系统:不是一个集中、统一的操作系统。它基本上是在各种各样自治的计算机原有操作系统基础上加上具有各种网络访问功能的模块,这些模块使网络上的计算机能方便、有效地共享网络资源,实现各种通信服务的有关协议。
5. 嵌入式操作系统和智能卡操作系统
分布式操作系统与网络操作系统的区别
1).资源管理
网络操作系统各个主机独立管理自己的资源;分布式则由一台主机统一管理系统中的资源
2).用户感觉
网络操作系统用户面对多台主机;分布式用户好像在使用同一台主机
3).操作方式
网络操作系统是多用户操作;分布式是单用户操作
嵌入式操作系统(EOS)
概念: 运行在嵌入式芯片环境中,对整个芯片以及它所操作和控制的各种部件装置等资源进行统一协调、调度、指挥和控制的系统软件。
目前大多数的嵌入式操作系统主要提供以下3种项目的机制:
1)内存管理
2)多任务调度
3)外围资源管理
嵌入式操作系统的优点:具有高可靠性、实时性、占有资源少和低成本等。
嵌入式操作系统区别于通用操作系统的一些重要特征:
体积小、运行时间长、故障重启、低功耗、价格便宜、动态加载。
作业(job)的概念:
请求计算机完成的一个完整的处理任务称为作业,它可以包括几个程序的相继执行。
用户在键盘上输入的一条完整的命令就是一个作业。
复杂的作业也可由作业说明书(如Shell命令程序)来描述。一个复杂的作业可由多个作业步组成,如编译、运行、打印一个程序的全部工作是一个作业,其中相对独立的每一部分称为作业步。
进程概念
程序在一个数据集合上的运行活动,它是系统进行资源分配和调度的一个可并发执行的独立单位。
进程与程序的区别与联系
进程与程序的区别:
程序是一组指令的集合,它是静态的实体,没有执行的含义。
进程是一个动态的实体,有自己的生命周期。一般说来,一个程序可以只有一个进程,也可有多个进程;一个进程可以同这个程序相对应,也可以同另一个程序相对应。
进程与程序的联系:
进程为应用程序的运行实例,是应用程序的一次动态执行。
操作系统的功能
处理机管理
存储管理
设备管理
文件管理
用户接口
操作系统的分类
最基本的操作系统类型有哪三类?多任务操作系统、分时操作系统和实时操作系统。
Linux有4个基本组成部分,并简要说明各自功能。
答:内核、shell、文件系统和应用程序。
Linux内核:是一个操作系统最基本的组成部分,由它来向应用程序访问硬件时提供服务。
Linux shell:是系统的用户界面,提供用户与内核的交互接口。实际上shell是一个命令解释器,它接收并解释用户输入的命令并把它们送到内核。
Linux文件系统:是文件存放在磁盘等存储设备上的组织方法。Linux支持多种目前流行的文件系统,如EXT2、EXT3、FAT、VFAT、IS09660、NFS、SMB等。
Linux应用程序:标准Linux系统都有一套称为应用程序的程序集,包括文本编辑器、编程语言、X Window、办公套件、Internet工具、数据库等。
Linux运行写好的外壳脚本文件的四种方法
1) 修改外壳脚本的权限:可以把外壳脚本的权限设置为可执行,在外壳提示符下直接执行;也可使用chmod命令更改外壳脚本的权限。
2) 通过向外壳命令传递参数。
在调用执行的外壳命令后面跟随外壳脚本的文件名作为命令行参数。
(3) 在pdksh和bash下使用.命令,或在tcsh下使用source命令。
(4)使用命令替换。
如果想要使某个命令的输出成为另一个命令的参数时,就可以使用这个方法。我们将命令列于两个’号之间,而外壳会以这个命令执行后的输出结果代替这个命令以及两个’符号。
Linux内核版本号由3个数字组成:r.x.y
r:目前发布的Kernel主版本。
x:偶数:稳定版本;奇数:开发中版本。
y:错误修补的次数。
一般来说,x位为偶数的版本是一个可以使用的稳定版本,如2.4.4;x位为奇数的版本一般加入了一些新的内容,所以性能不一定很稳定,仍是处于测试阶段,系统是一个测试版本,如2.5.5。
VFS
“虚拟文件系统”VFS(VFS是Virtual File System的缩写,或是Virtual Filesystem Switch缩写)概念
VFS由一组标准的、抽象的文件操作构成,以系统调用的形式提供于用户程序,如read()、write()、lseek()等。用户程序可以把所有的文件都看作一致的、抽象的“VFS文件”。
常用linux编辑器
常用的linux编辑器有很多,比如图形模式下的gedit、kwrite、OpenOffice,文本模式下的VIM、Emacs和nano。
VIM和Emacs是我们在Linux下最常用的两个编辑器。
VIM编辑器概念
VIM是Linux最基本的文本编辑工具,是创建和编辑简单文档最高效的工具。尤其适用于没有安装xWindows桌面环境或桌面环境崩溃等场合。
VIM的模式一般分成三种
一般模式。进入VIM就是处于一般模式,只能通过按键向编辑器发送命令,不能输入文字。这些命令可能是移动光标的命令,也可能是编辑命令或寻找替换命令。
编辑模式。在一般模式下按i(有些教材也称之为插入模式),此时可以键入文字,写你的文章,按Esc就又回到一般模式。
命令模式。在一般模式下按:就会进入命令模式,左下角会有一个冒号出现,此时可敲人命令并执行。按Esc回到一般模式。
shell简介
shell是一种具备特殊功能的程序,它是介于使用者和Unix/Linux操作系统内核间的一个接口。简单地说,shell就是一个命令解释器。用户可以用shell来启动、挂起、停止甚至是编写一些程序。
计算机对于命令的接收和处理则需要用到shell,shell首先向用户提供了一个界面系统,用户通过该界面可以向计算机发出指令,同时,shell对命令进行解释,并向内核提出请求。
在shell程序中还可以执行一些批处理命令,这些批处理命令在Linux中叫做外壳脚本(shell script)。
Shell Script定义: 在shell程序中执行一些批处理命令,这些批处理命令在Linux中叫做外壳脚本。
不同外壳的脚本会有一些差异,写给A外壳的脚本一般不能在B外壳中执行。Linux系统最常用的外壳有Bourne外壳和C外壳。
嵌入式Linux系统开发平台
(1)嵌入式Linux的软件操作平台
嵌入式Linux系统需要三个基本元素:
系统引导工具(用于机器加电后的系统定位引导)、Linux微内核(内存管理、程序管理)、初始化进程
如果要成为完整的操作系统并且继续保持小型化,还必须加上:硬件驱动程序、硬件接口程序和应用程序组。
GCC是基于GNU的编译器套件,作为GNU工具链的一部分,与gdb调试器一起工作。它提供了开发嵌入式Linux系统的所有软件工具。
(2)嵌入式Linux系统硬件平台
如果要寻找嵌入式软件系统,那么,应首先确定硬件平台,即确定微处理器CPU的型号。硬件开发成本常是开发者很关心的。当考虑硬件成本时,需要考虑产品的整个成本而不仅是CPU的成本。因为合适的CPU,一旦加上总线逻辑和延时电路使之与外设一起工作,硬件系统就可能变得非常昂贵。
生成嵌入式开发工具链的流程图
根据生成嵌入式开发工具链的流程图简述在redhat Linux9.0环境下建立基于ARM+Linux的嵌入式开发工具链的过程。
选定软件版本
选用适当的版本,找到适合主机和目标板的组合。
建立工作目录
设置输出环境变量
*内核头文件的配置
内核头文件的配置是建立工具链的第一步。它与后面将要执行的其他步骤有着类似性,大多需要执行下面几步操作:
解压缩包、为跨平台开发设定包的配置、建立包、安装包
其中,进行配置时,变量ARCH和CROSS_COMPILE的值与目标板的架构类型有关。
如果使用PPC目标板,则 ARCH=ppc CROSS-COMPILE=ppc-linux-。
如果使用i386目标板,则:ARCH=i386 CROSS-COMPILE=i386-linux-。
本例中,配置的具体参数是:
$make ARCH=arm CROSS-COMPILE=arm-linux- menuconfig
配置工具选择:
make menuconfig是以文本菜单方式配置。
make xconfig是以图形界面方式配置。
make config是纯文本界面方式配置。
设置binutils二进制工具程序
binutils包中的工具常用来操作二进制目标文件。该包中最重要的两个工具就是GNU汇编器as和链接器ld。
因为是交叉编译器,还不需要目标板的系统头文件,所以需要使用-without-headers这个选项。
-enable-language=c用来告诉配置脚本,需要产生的编译器支持何种语言,现在只能支持c语言。
初始编译器的建立
开始只能建立支持C语言的引导编译器,因为缺少C链接库(glibc)的支持。等到glibc编译好之后,可以重新编译gcc并提供完整的C++支持。
建立C库(glibc)
这一步是最为繁琐的过程。目标板必须靠它来执行或者是开发大部分的应用程序。glibc套件常被称为C链接库,但是glibc实际产生很多链接库,其中之一是c链接库libc。因为嵌入式系统的限制,标准GNU C链接库显得太大,不适合应用在目标板上。所以需要寻找c链接库的替代品,比如uclibc。
完整编译器的设置
为目标板安装支持C和C++的完整编译器。这个步骤相对于前面的建立过程要简单一些。具体命令:
$cd $PRJROOT/build-dir/build-gcc
$.. /.. /src-dir/gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX
--enable-languages=c,c++
$make all
$make install
完整工具链的设置
GDB简介
调试器GDB能让你观察另一个程序在执行时的内部活动,或程序出错时发生了什么。
GDB的主要功能
完成以下四件事,帮助找出程序中的错误。
(1)运行程序,设置所有的能影响程序运行的东西。
(2)保证程序在指定的条件下停止。
(3)当程序停止时,让你检查发生了什么。
(4)改变程序。那样你可以试着修正某个bug引起的问题,然后继续查找另一个bug。
在文本编辑器emacs中编写一个简单的C程序,使用嵌入式开发工具链编译,并用gdb调试的例子。
$cd $PRJROOT/program
$emacs hello.c
在文本编辑器emacs中编写:
#include <stdio.h>
int main()
{
int i;
for(i=1;i<9;i++)
printf(“Hello World%d times!\n”,i);
}
保存退出。
$gcc -g hello.c -o hello
$gdb
(gdb)file hello
(gdb)l
#include<stdio.h>
int main()
{
int i;
for(i=1;i<9;i++)
printf(“Hello World%d times!\n”,i);
}
(gdb)r
(gdb)q
$arm-linux-gcc -g hello.c -o hello-linux
$file hello-linux
hello-linux:ELF 32-bit LSB executable,ARM,version 1(ARM),for GNU/Linux2.0.0,
dynamically linked(uses shared libs),not stripped
上面的输出说明已成功编译了一个能在arm体系结构下运行的hello-linux,证明编译工具安装成功了。
普通PC的引导装载程序组成:BIOS和BootLoader。
BIOS负责完成硬件检测和资源分配。BIOS完成任务后,会将控制权交给系统的BootLoader;
BootLoader将操作系统内核从硬盘上读入RAM中,然后跳转到内核的入口点,从而启动操作系统。
嵌入式系统由于硬件资源的限制,通常没有像BIOS那样的固件程序(注:有的嵌入式CPU也会内嵌一段短小的启动程序)。整个系统的加载启动全部由BootLoader来处理。
BootLoader定义
BootLoader就是在运行操作系统内核之前所运行的一段小程序。将系统的软硬件设置为一个合适的环境,以便为最终调用操作系统内核做好准备。
BootLoaderd的基本功能
对系统的硬件设备进行初始化;
建立内存空间的映射图;
将系统的软硬件设置为一个合适的环境,以便为最终调用操作系统内核做好准备。
BootLoader的操作模式
大多数BootLoader都包含两种不同的操作模式:“启动加载模式”和“下载模式”。
启动加载(bootLoading)模式:也称为“自主”(autonomous)模式。也即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是BootLoader的正常工作模式。在嵌入式产品发布的时侯,BootLoader必须工作在这种模式下。
下载(down loading)模式:该模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机(host)下载文件。工作于这种模式下的BootLoader通常都会向它的终端用户提供一个简单的命令行接口。
BootLoader与主机之间的通信方式
主机和目标机之间一般通过串口建立连接,BootLoader软件在执行时通常会通过串口来进行输入输出。传输协议通常是xmodem/ymodem/zmodem协议中的一种。但是,串口传输的速度是有限的。因此,可通过以太网连接并借助TFTP协议来下载文件。
BootLoader总体流程
由于BootLoader的实现依赖于CPU的体系结构,因此大多数BootLoader都分为stage1和stage2两大部分。
依赖于CPU体系结构的代码通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的,一般不会超过 256Byte; 由于是在内核启动前运行的第一个程序,因此它是在flash上运行的;有的文献把这一阶段称为“Flashloader”阶段。
stage2的代码量大,有上千行;通常用C语言来实现,多数时候需要嵌入汇编语言,可以实现复杂的功能;代码具有更好的可读性和可移植性;在SDRAM等随机存储器中运行;这一阶段是真正的“BootLoader”阶段。
在ARM体系中通常有3种方式控制程序的执行流程
(1)在正常程序执行过程中,每执行一条ARM指令,程序计数器(PC)的值加4个字节;每执行一条Thumb指令,程序计数器寄存器(PC)的值加2个字节。整个过程按序执行。
(2)通过跳转指令,程序可以跳到指定的地址标号处执行。或者跳到指定的子程序执行。
(3)当异常中断发生时,系统执行完当前指令后,将跳转到相应的异常中断处理程序处执行。在当异常中断处理程序执行完成后,程序返回到发生中断的指令的下条指令处执行。在进入异常中断处理程序时,要保存被中断的程序的执行现场,在从异常中断处理程序退出时,要恢复被中断的程序的执行现场。
一套完整的开发工具应至少包括以下三种工具
编辑工具、编译工具和调试工具。如果是大型项目,还要有配置工具和项目管理工具。
开发环境
开发环境分为基于文本的开发平台(典型组合是vim/emacs + gcc + gdb)和集成开发平台(Eclipse+CDT插件)。
GCC概念
GCC是GNU项目的编译器套件,能够编译用C、C++和Objective C编写的程序。
GCC的基本用法:gcc[options][filenames]
该命令行使gcc在给定文件(filenames)上执行编译选项(options)指定的操作。
一个基本实例:
//test.c
#include <stdio.h>
void main()
{
printf(”Hello world!\n”);
}
使用gcc编译器编译一下: gcc -c test.c
用户将会在同一目录下得到一个名为a.out的文件,然后在命令提示符下执行 $./a
就可以显示结果Hello world!。要注意的是a.out是默认生成的目标文件名,如果在同一个目录下,编译另外一个源程序且没有指明生成的目标文件名的话,原先的a.out文件会被覆盖。我们可以使用-o选项指定生成的目标文件名,如
gcc -o test -c test.c
这样在同一目录下会生成名为test.o的目标文件,然后执行$./test即可,会得到同样的输出Hello World!。
GNU make管理项目
当使用GNU中的编译语言如GCC、GNU C++编程开发应用时,绝大多数情况要使用make管理项目。要使用make进行项目管理必须编写Makefile文件。
Makefile文件是一个文本形式的数据库文件,其中包含的规则指明make编译哪些文件以及怎样编译这些文件。
一条规则包含3方面内容:make要创建的目标文件(target),编译目标文件所需的依赖文件列表(dependencies),通过依赖文件创建目标文件所需要执行的命令组(commands)。
为什么要使用make?
首先,包含多个源文件的项目在编译时都有长而复杂的命令行,使用make可以通过把这些命令行保存在makefile文件中而简化这个工作;
其次,使用make可以减少重新编译所需要的时间,因为它可以识别出那些被修改的文件,并且只编译这些文件;
最后,make在一个数据库中维护了当前项目中各文件的相互关系,从而可以在编译前检查是否可以找到所有需要的文件。
当登录linux系统,并打开终端。根据登入的身份,进入终端后会看到如下提示符:
[root@tty/]# 或pear@ubuntu:~$
其中,root和pear表示 登录用户 。其中,root表示登录用户是超级用户,pear表示表示登录用户是普通用户。Tty和 ubuntu均表示网络中主机名 ,/和 ~ 均表示登录用户的当前目录 (当登录用户,登录主机名以及进入目录不同时,相应的项也会改变),#表示登录用户是超级用户root ,如果是一般用户则为 $ 。
Makefile规则通用形式如下
target:dependency file1 dependency file2[…]
commandl
command2
[…]
注意:每一个命令行的首字符必须是Tab制表符,仅使用8个空格不够。除非特别指定,否则make的工作目录就是当前目录。
一个简单的Makefile实例:
printer:printer.o shape.o op_lib.o
gcc -o printer printer.o shape.o op_lib.o
printer.o:printer.c printer.h shape.h op_lib.h
gcc -c printer.c
shape.o:shape.c shape.h
gcc -c shape.c
op_lib.o:op-lib.c op_lib.h
gcc -c op_lib.c
clean:
rm printer *.o
第一行中的三个依赖文件并不存在,如果是在shell上用命令行编译则会出错并退出,但在make管理项目中,在执行gcc时会先检查依赖文件是否存在,若不存在,则会先执行别的规则以生成缺少的依赖文件,最后生成相关的目标文件。如果依赖文件已经存在,则并不急于执行后面的命令重新得到它们,而是比较这些依赖文件以及与其对应的源文件的生成时间,如果有一个或多个源文件比相应依赖文件新,则重新编译这些文件以反映相关源文件的变化,否则,使用旧的依赖文件生成目标文件。
编写Makefile文件的规则
(1) 伪目标
由于伪目标没有依赖文件,它不会自动执行。
原因是:make在执行到伪目标时,make先检查它的依赖文件是否存在,由于伪目标没有依赖文件,make就认为该目标是最新版本,不需要重新创建。要想启动伪目标必须使用如下命令:make[virtual target]。
(2) 变量
编写Makefile时也可以使用变量,所谓变量就是用指定文本串在Makefile中定义的一个名字,Makefile中变量一般用大写,并用等号给它赋值。引用时只需用括号将变量名括起来并在括号前加上$符号。如:VARNAME=some-text
当编写大型应用程序的Makefile时,其中涉及的依赖文件和规则繁多,如果使用变量表示某些依赖文件的路径,则会大大简化Makefile。一般在Makefile文件开始就定义文件中所需的所有变量,这样使Makefile文件清晰且便于修改。如(#在Makefile文件中表示后面的内容是注释):
(3) make变量
make管理项目也允许在Makefile中使用特殊变量,即make变量。make变量包括环境变量、自动变量和预定义变量。
环境变量就是系统环境变量,make命令执行时会读取系统环境变量并创建与其同名的变量,但是如果Makefile有同名变量,则用户定义变量会覆盖系统的环境变量值。
需对ARM-Linux内核裁减的原因
进行嵌入式系统开发时,由于受到硬件资源和环境等因素的影响,必须对Linux内核进行裁减,以适应硬件的需求或者某些环境特殊的实际要求。
Linux内核的配置系统由以下3部分组成
Makefile:Linux内核源代码中的Makefile定义Linux内核的编译规则。
配置文件(config.in):给用户提供配置选择的功能。
配置工具:包括配置命令解释器和配置用户界面。这些配置工具都是使用脚本语言,如Tcl/TK、Perl编写的。
内核空间和用户空间的概念
内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。这种系统态和被保护起来的内存空间统称为内核空间。
应用程序在用户空间执行。它们只能看到允许它们使用的部分系统资源,并且不能使用某些特定的系统功能,不能直接访问硬件,还有其他一些使用限制。
用户空间内应用程序的开发与内核开发间最重要的差异包括
内核编程时不能访问C库。
内核编程时必须使用GNU C。
内核编程时缺乏像用户空间那样的内存保护机制。
内核编程时浮点数很难使用。
内核只有一个很小的定长堆栈。
内核支持异步中断、抢占和SMP (Symmetric Multi-Processor, 对称式多处理器),因此须注意同步和并发。
要考虑可移植性的重要性。
VFS(虚拟文件系统)概念
VFS由一组标准的、抽象的文件操作构成,以系统调用的形式提供于用户程序,如read()、write()、lseek()等。这样,用户程序就可以把所有的文件都看作一致的、抽象的“VFS文件”,例如,在Linux操作系统中,可以按DOS格式的磁盘或分区(即文件系统)“安装”到系统中,然后用户程序就可以按完全相同的方式访问这些文件,就好像它们也是Ext2格式的文件一样。
嵌入式系统加电或复位后,所有的CPU通常都从某个由CPU制造商预先安排的地址上取指令。
比如,基于ARM7TDMI内核的CPU在加电或复位时,通常都从地址0x00000000取它的第一条指令。而基于这种CPU构建的嵌入式系统,通常都有某种类型的固态存储设备被映射到这个预先安排的地址上。从而可以使系统在加电后,CPU首先执行BootLoader程序。
BootLoader、内核启动参数以及其它的系统映像在固态存储设备上的分配结构大都如图所示:
52. Bootloader启动流程示意图
以 “Hello World!”程序为例。简述进行嵌入式Linux C语言简单应用程序开发的流程。(编写源程序、编译、调试,并在嵌入式设备上运行)
1 编写源程序
首先打开编辑器VIM。在Linux PC上打开一个终端窗口,输入命令vi helloworld.c,打开并建立源文件。输入源代码
2 交叉编译程序
在Helloworld.c所在的目录中建立Makefile文件,Makefile文件保存好后,接下来就可以在helloworld.c文件目录下执行make命令进行编译了。编译后会产生ARM-Linux下的可执行文件helloworld,可以将此文件下载到目标板进行调试运行。
3 调试程序
通常采用gdb+gdbserver的方式进行调试,采用远程调试(remote)的方法。
1)建立安装gdb组件
2)调试运行
3)调试命令(注意命令列表中括号里的内容为命令简写方式)
(2023年2月14日 22:10首次发布)