全分离。因此运行一个应用的进程不会影响其他的进程。同样,硬件的虚拟内存机制允许内存区域被写保护,这样保护了代码和数据不被恶意应用重写。
3)内存映射:用来把映像和数据文件映像到一个进程的地址空间。在内存映射中,文件的内容被直接链接到进程的虚拟地址空间。
4)公平物理内存分配:内存管理子系统分配给系统中运行的每个进程公平的一份系统物理内存。
5)共享虚拟内存:允许进程拥有分隔的虚拟地址空间,但有时还需要进程共享内存。如进程间通信需要共享内存。
7、?C/OS-II的主要特点有哪些?简要说明之。(P121)
答:?C/OS-II的主要特点有: 1)公开源代码
2)可移植性(Portable)
绝大部分?C/OS-II的源码是用移植性很强的ANSI C写的。和微处理器硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低限度,使得?C/OS-II便于移植到其他微处理器上。?C/OS-II可以在绝大多数8位、16位、32位以至64位微处理器、微控制器、数字信号处理器(DSP)上运行。
3)可固化(Romable)
?C/OS-II是为嵌入式应用而设计的,这就意味着,只要读者有固化手段(C编译、连接、下载和固化),?C/OS-II可以嵌入到读者的产品中成为产品的一部分。
4)可裁剪(Scalable)
可以只使用?C/OS-II中应用程序需要的那些系统服务。也就是说某产品可以只使用很少几个?C/OS-II调用,而另一个产品则使用了几乎所有?C/OS-II的功能,这样可以减少产品中的?C/OS-II所需的存储器空间(RAM和ROM)。这种可剪裁性是靠条件编译实现的。
5)占先式(Preemptive)
?C/OS-II是完全占先式的实时内核,?C/OS-II总是运行就绪条件下优先级最高的任务。 6)多任务
?C/OS-II可以管理64个任务,目前这一版本保留8个给系统。留给用户的应用程序最多可以有56个任务。赋予每个任务的优先级必须是不相同的,这意味着?C/OS-II不支持时间片轮转调度法(常用的非抢占式调度算法)。
7)可确定性
全部?C/OS-II的函数调用与服务的执行时间具有可确定性。 8)任务栈
每个任务有自己单独的栈,?C/OS-II允许每个任务有不同的栈空间,以便压低应用程序对RAM的需求。
9)系统服务
?C/OS-II提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存的申请与释放、时间相关函数等。
10)中断管理
中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。
8、常用的linux操作系统采用怎样的内存管理机制和调度机制?(P130)
答:Linux内存管理程序通过映射机制把用户程序的逻辑地址映射到物理地址,在用户
程序运行时,如果发现程序中要用的虚拟地址没有对应的物理内存时,就发出请页要求。如果有空闲的内存可供分配,就请求分配内存,并把正在使用的物理页记录在页缓存中;如果没有足够的内存可供分配,那么就调用交换机制,腾出一部分内存。为了支持虚拟存储器的管理,Linux系统采用分页(paging)的方式来载入进程。所谓分页即是把实际的存储器分割为相同大小的段,例如每个段1024个字节,这样1024个字节大小的段称为一个页面(page)。
Linux属于典型的多用户多任务操作系统。它采用分时技术,进程交替执行,实现所谓的“假并行”。它主要有三种调度算法,一个是基于优先级的循环执行法,二是FIFO算法,三是传统的基于优先级的循环执行法。前两种调度算法都是软实时的,而第三种则并非实时的。
第6章 嵌入式Linux开发环境及其在ARM上的移植
1、试述嵌入式Linux系统移植的一般过程。(P141~142)
答:嵌入式系统的开发和应用层软件的开发不同,有其自身的特点,尤其在开发流程上有很大的不同。从大体上讲,Linux系统移植一般分为下面几步:
(1)开发环境的搭建 嵌入式系统移植过程中,目标机和宿主机往往在软硬件环境上有很大的不同,开发时常常在功能强大的宿主机上进行,这就形成了交叉开发环境的搭建与选择问题。同时由于宿主机和目标机在体系结构等方面的差异,编译时也需要采用交叉编译工具对目标代码进行编译,这样,才能使生成的可执行文件在目标机上能够执行。
(2)系统引导
在微处理器第一次启动的时候,会从预定的、固定的地址空间开始执行指令。一般的嵌入式系统中并没有PC机上的BIOS,而是由一种称为Bootloader的系统引导程序来完成上述功能,启动代码完全依赖于硬件,需要在系统移植中完成。
(3)内核引导
系统移植的开发人员还应当完成Bootloader和内核的衔接部分的移植以及I/O映射、存储器映射等与目标硬件平台相关的板级初始化和CPU自身初始化的移植工作。
(4)设备驱动程序
Linux内核源代码树中的相当大部分是各类驱动程序,在实际的开发过程中,也需要对相应的设备进行驱动,如LCD、网卡、触摸屏等等进行移植和编写。由于一般在Linux源码和相关社区中都拥有相当丰富的设备驱动源码资源,因此,设备驱动的任务主要是相近源码的移植修改工作。
(5)文件系统
在嵌入式Linux内核启动的最后阶段,将进行文件系统的加载。不同的嵌入式目标平台有不同的应用需求,需要根据具体情况实现对文件系统的移植工作。目前,常用的嵌入式文件系统有JFFS2、Cramfs、Romfs等。
2、Linux系统中常用的交叉编译工具有哪些?简述它们的功能和基本用法。(P143~153)
答:(1)GNU binutils是一套用来构造和使用二进制所需的工具集。建立嵌入式交叉编译环境,Binutils工具包是必不可少的,而且Binutils与GNU的C编译器gcc是紧密相集成的,没有binutils,gcc也不能正常工作。GNU binutils是一组开发工具,包括连接器、汇编器和其他用于目标文件和档案的工具。
(2)GUN cc(GUN C Compiler,简称gcc)是GUN项目的C编译器套件,能够编译用C、C++、Objective C编写的程序。
(3)make工具通过一个称为makefile的文件来完成并自动维护编译工作。
(4)glibc 是提供系统调用和基本函数的C库,比如open,malloc,printf等等。所有动态连接的程序都要用到它。它是编译Linux系统程序很重要的组成部分。
(5)gdb是一个用来调试C和C++程序的调试器(Debugger),它能使用户在程序运行时观察程序的内部结构和内存的使用情况。gdb的功能主要是监视程序中变量的值、设置断点以使程序在指定的代码行上停止执行、支持单步执行等。
3、如何分步编译和安装交叉编译环境所需要的库和源代码?试着自己构建嵌入式Linux系统交叉编译环境。(P156~160) 答:[略]
4、5题应在第九章,此处为作者疏漏(见第九章习题)
6、Linux操作系统的移植工作主要分为哪几个方面?其中内核功能模块的裁剪主要有哪几种方法?(P162~164)
答:对Linux操作系统的移植工作主要分为两个方面,一方面是针对硬件特点对源代码的修改,比如内核的启动部分、存储设备的大小、具体的驱动问题等等;另一方面是功能模块的裁剪,主要是对内核功能的配置,包括支持的文件类型、外设模块等等。
总体上讲,针对硬件的修改有两种方法:
(1)对一种全新的硬件平台开展移植工作时,需采用“自底向上”的设计方法从头设计,即从硬件的需求考虑逐步地采用分析、设计、编码、测试。
(2)大多数情况下,是在前人工作的基础上修改己有的代码。Linux己经可以在多种体系结构中运行,可以参考相近的体系结构的代码,修改与目标硬件平台不同的部分即可。
嵌入式Linux内核功能模块的裁剪主要有三种方法: (1)使用Linux自身的配置工具,编译定制内核。 (2)修改内核源代码,进行内核裁剪。 (3)基于系统调用关系,进行内核裁剪
7、如何使用Linux自身的配置工具编译定制内核?(P169)
答:配置完内核之后,内核仍然以源代码的方式存在,不能直接下载到嵌入式系统中运行,因此,必须对内核进行编译,生成最终在目标板上运行的可执行代码。
编译内核分以下三步进行:
(1)执行以下命令,正确设置编译内核所需的附属文件,进行依赖性编译:# make dep (2)执行以下命令,清除以前构造内核时产生的所有目标文件、模块文件和一些临时文件:# make clean
(3)执行以下命令,生成新的可执行内核映像文件:# make zImage
完成上述命令之后,就会在/arch/arm/boot/下生成一个自己定制的内核映像文件了,系统文件名可以任意取,如zImage.rom。
8、什么是文件系统?常用的嵌入式文件系统有哪些?(P169~170)
答:文件系统是指在一个物理设备上的任何文件组织和目录,它构成了Linux系统上所有数据的基础,Linux程序、库、系统文件和用户文件都驻留其中,因此,它是系统中庞大
复杂且又是最为基本和重要的资源。通常对于一个嵌入式系统,仅包含内核是不够的,还必须有文件系统的支持。
Linux支持的文件系统有很多种,比如ext2(LinuxExtended-2)、minix文件系统、msdos(最初的FAT文件系统)、ntfs(WindowsNT文件系统)、nfs(网络文件系统)、hpft(OS/2高性能文件系统)、ncpfs(NovellNetWare文件系统)、affs Amiga(快速文件系统)等等。
9、如何构建一个嵌入式Linux文件系统?(P172)
答:要构建一个小型的Linux文件系统,就需要决定文件系统中哪些部分要保留,哪些部分可以裁减。首先应该保留那些保证系统运行的最基本的文件和目录,再通过对系统功能的分析,决定哪些模块是可以裁减的。
一个最小的文件系统必须包括以下的内容:程序函数库、库函数文件的链接、/bin/sh(shell)、最基本的设备文件。
但是,这些文件目录组成的最基本的文件系统只能运行shell,不能完成其它任何的应用程序。要完成一些基本的功能还需要以下的一些文件:init程序、系统启动设置、基本的应用程序、设备文件、显示系统信息的虚拟文件系统、其它文件系统挂载目录、系统启动时执行的脚本、压缩工具等。
第7章 linux下设备驱动程序的开发设计
1、设备驱动程序在大多数嵌入式系统中起着重要作用,因为它们提供了 应用程序 和 设备 之间的软件层。
2、设备驱动程序通常包含 中断处理程序 和 设备服务子程序 两部分。
3、嵌入式系统中_____A____、___C_______、_____D___等都属于字符设备,典型的块设备有_____B_____、____E______等。
A.按键 B.硬盘 C.触摸屏 D.手写板 E.CD-ROM
4、系统中不同的设备有_____A_____主设备号,主设备号 A 设备使用____A______驱动程序。
A.相同的 B.不同的
5、CS8900A有两种工作模式:MEMORY模式和IO模式。
6、如何理解设备管理的“设备无关性”概念?(P174)
答:在Linux/uclinux的框架结构中,和设备相关的处理可以分为两个层次——文件系统层和设备驱动层。设备驱动层屏蔽具体设备的细节,文件系统层则向用户提供一组统一的、规范的用户接口。在嵌入式操作系统下的设备驱动程序主要是控制和管理下层物理设备的硬件控制器,同时为上层应用提供统一的、与设备无关的系统调用服务,这种设备管理方法称为“设备无关性”。
7、按模块化设计,一个典型的Linux设备驱动程序应包含哪几部分?在Linux操作系统中如何实现一个驱动程序的开发?(P177)
答:一个典型的Linux设备驱动程序应包含以下几部分代码:驱动程序模块的注册与注销函数、设备的打开、关闭、读、写及需要的其他操作函数、设备的中断服务程序。
在Linux操作系统中实现一个驱动程序的开发,必须按照如下步骤进行:设备或模块的初始化;实现该文件操作接口;注册了设备中断;编写中断服务程序;文件读写操作。
8、Linux中的设备可以分为哪几类,各有何特点?(P177~179)
答:Linux中的设备可以分为三类:字符设备、块设备和网络设备。各自的特点是:字符设备是指数据处理以字节为单位按顺序进行的设备,它没有缓冲区,不支持随机读写。在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了。块设备是指那些在输入/输出时数据处理以块为单位的设备,它一般都采用了缓存技术,支持数据的随机读写。网络设备面向的上一层不是文件系统层而是网络协议层,设备节点只有在系统正确初始化网络控制器之后才能建立。内核和网络设备驱动程序间的通信,与字符设备驱动程序、块设备驱动程序与内核间的通信也是完全不一样的。在Linux中,整个网络接口驱动程序的框架可分为四层,从上到下分别为协议接口层、网络设备接口层、提供实际功能的设备驱动功能层、以及网络设备和网络媒介层。
9、如何理解驱动程序的设备文件接口?(P182) 答:略。
10、详细描述在Linux操作系统下CS8900A网络芯片驱动程序的实现。(P194) 答:Linux操作系统下CS8900A网络芯片驱动程序的实现按照如下步骤进行: (1)初始化CS8900A芯片
对于CS8900A芯片,初始化函数是通过cs89x0_probe()和cs89x0_probe1()函数来实现。 int cs89x0_probe(struct device *dev) {
int base_addr = CS8900_BASE;
return cs89x0_probe1(dev,base_addr); }
其中CS8900_BASE是I/O被映射到的基地址。 static int cs89x0_probel(struct device *dev, int ioaddr) {
irq2dev_map[0] = dev; ……
/* 初始化寄存器,建立片选和芯片工作方式*/
*(volatile unsigned char *)0xfffff42b |= 0x01; /* output /sleep */ *(volatile unsigned short *)0xfffff428 |= 0x0101; /* not sleeping */ *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ *(volatile unsigned short *)0xfffff428 &= ~0x0202;/* irq5 fcn on */ *(volatile unsigned short *)0xfffff102 = 0x8000; /* 0x04000000 */
*(volatile unsigned short *)0xfffff112 = 0x01e1; /*128k,2ws,FLASH,en*/ ??
/* 初始化设备结构*/
if (dev->priv == NULL){
dev->priv = kmalloc(sizeof(struct net_local),GFP_KERNEL);