第一章概述1、什么是POSIX标准,为什么现代造作系统的设计必须遵循POSIX标准?答:POSIX表示可移植操作系统接口(PortableOperatingSystemInterface)。POSIX是在Unix标准化过程中出现的产物。POSIX1003.1标准定义了一个最小的Unix操作系统接口。任何操作系统只有符合这一标准,才有可能运行Unix程序。2、什么是GNU?Linux与GNU有什么关系?答:GNU是GNUIsNotUnix的递归缩写,是自由软件基金会的一个项目。GNU项目产品包括emacs编辑器、著名的GNUC和Gcc编译器等,这些软件叫做GNU软件。GNU软件和派生工作均适用GNU通用公共许可证,即GPL(GeneralPublicLicense)。Linux的开发使用了众多的GUN工具。3、Linux系统由哪些部分组成?Linux内核处于什么位置?答:(1)符合POSIX标准的操作系统内核、Shell和外围工具。(2)C语言编译器和其他开发工具及函数库。(3)XWindow窗口系统。(4)各种应用软件,包括字处理软件、图象处理软件等。Linux内核是所有Linux发布版本的核心。第二章内存寻址1、在80x86的寄存器中,哪些寄存器供一般用户使用?哪些寄存器只能被操作系统使用?答:通用寄存器EAX,EBX,ECX,EDX,EBP(基址指针),ESP(堆栈指针),ESI(扩展源指针),EDI(扩展目的指针),还有EFLAGS(标志寄存器).专供操作系统使用的寄存器:IDTR中断描述符寄存器,GDTR全局描述符表寄存器,LDTR局部描述符表寄存器,TaskRegisters任务寄存器,DebugRegister调试寄存器,ControlRegister控制寄存器,Model-SpecificRegisters模型专用寄存器。3、请用C语言描述段描述符表。答:#includestdio.h#includestdlib.h#defineBASE_H0xff00#defineBASE_M0x00ff#defineBASE_L0xffff#defineLIMIT_H0x000f#defineLIMIT_L0xffff#defineGRANULARITY0x0080#defineSEGMENT_P0x8000#defineSYSTEM_TYPE0x1000#defineDPL0x6000#defineTYPE_E0x0800#defineTYPE_ED_C0x0400#defineTYPE_RW0x0200#defineTYPE_A0x0100struct{unsignedcharbase_high;unsignedcharg:1;unsignedcharother:3;unsignedcharlimit_high:4;unsignedcharP:1;unsignedchardpl:2;unsignedcharS:1;unsignedcharE:1;unsignedcharED_C:1;unsignedcharRW:1;unsignedcharA:1;unsignedcharbase_middle;unsignedshortbase_low;unsignedshortlimit_low;}gdt_t;intmain(intargc,char*argv[]){//intgdt[4]={0x0fff,0x0000,0x9a00,0x00c0};//0x08//intgdt[4]={0x7fff,0x0000,0x9a01,0x00c0};//0x10//intgdt[4]={0x0002,0x8000,0x920b,0x00c0};//displaymemory//intgdt[4]={0xffff,0xffff,0xffff,0xffff};//testintgdt[4]={0x03ff,0x0000,0xf201,0x00c0};//ldt0unsignedintbase,limit;unsignedintgranularity;unsignedintpresent,dpl,system_type,segment_type;unsignedinttype_e,type_ed_c,type_rw,type_a;base=(gdt[3]&BASE_H)16;base+=(gdt[2]&BASE_M)16;base+=gdt[1]&BASE_L0;limit=(gdt[0]&LIMIT_L)0;limit+=(gdt[3]&LIMIT_H)16;granularity=(gdt[3]&GRANULARITY)7;present=(gdt[2]&SEGMENT_P)15;dpl=(gdt[2]&DPL)13;system_type=(gdt[2]&SYSTEM_TYPE)12;type_e=(gdt[2]&TYPE_E)11;type_ed_c=(gdt[2]&TYPE_ED_C)10;type_rw=(gdt[2]&TYPE_RW)9;type_a=(gdt[2]&TYPE_A)8;printf(base\t\t0x%x\t%d\n,base,base);printf(limit\t\t0x%x\t%d\n,limit,limit);printf(\n);printf(G\t\t%d\t(0=bype,1=4KB)\n,granularity);printf(\n);printf(P\t\t%d\n,present);printf(DPL\t\t%d\n,dpl);printf(S\t\t%d\t(0=system,1=codeordata)\n,system_type);printf(TYPE_E\t\t%x\n,type_e);printf(TYPE_ED_C\t%x\n,type_ed_c);printf(TYPE_RW\t\t%x\n,type_rw);printf(TYPE_A\t\t%x\n,type_a);printf(\n);printf(E=0,datasegment\n);printf(ED=0,datasegment\n);printf(ED=1,stacksegment\n);printf(W=0,notwritable\n);printf(W=1,writable\n);printf(\n);printf(E=1,codesegment\n);printf(C=0,ingoreprivilege\n);printf(C=1,useprivilege\n);printf(R=0,notreadable\n);printf(R=1,readable\n);returnEXIT_SUCCESS;}4、Linux是如何利用段机制又巧妙的绕过段机制的?在内核代码中如何表示各种段,查找最新源代码并进行阅读和分析。答:IA32规定段机制是不可禁止的,因此不可能绕过它直接给出线性地址空间的地址。万般无奈之下,Linux的设计人员干脆让段的基地址为0,而段的界限为4GB,这时任意给出一个偏移量,则等式为“0+偏移量=线性地址”,也就是说“偏移量=线性地址”。另外由于段机制规定“偏移量4GB”,所以偏移量的范围为0H~FFFFFFFFH,这恰好是线性地址空间范围,也就是说虚拟地址直接映射到了线性地址,我们以后所提到的虚拟地址和线性地址指的也就是同一地址。看来,Linux在没有回避段机制的情况下巧妙地把段机制给绕过去了。另外,由于IA32段机制还规定,必须为代码段和数据段创建不同的段,所以Linux必须为代码段和数据段分别创建一个基地址为0,段界限为4GB的段描述符。不仅如此,由于Linux内核运行在特权级0,而用户程序运行在特权级别3,根据IA32的段保护机制规定,特权级3的程序是无法访问特权级为0的段的,所以Linux必须为内核和用户程序分别创建其代码段和数据段。这就意味着Linux必须创建4个段描述符——特权级0的代码段和数据段,特权级3的代码段和数据段。5、为什么在设计两级页表的线性地址结构时,给页目录和页表各分配10位?如果不是这样,举例说明会产生什么样的结果?答:所谓两级页表就是对页表再进行分页。第一级称为页目录,其中存放的是关于页表的信息。4MB的页表再次分页(4MB/4K)可以分为1K个页,同样对每个页的描述需要4个字节,于是可以算出页目录最多占用4KB个字节,正好是一个页,其示意图如2.9所示。页目录共有1K个表项,于是,线性地址的最高10位(即22位~31位)用来产生第一级的索引。两级表结构的第二级称为页表,每个页表也刚好存放在一个4K字节的页中,包含1K个字节的表项。第二级页表由线性地址的中间10位(即21位~12位)进行索引,最低12位表示页内偏量。举例:如果页目录占用31~24位,页表项占用23~12位,偏移地址占11~0位,则有2^8个页表项,一个页面有2^12(4k)个表项,每个表项大小为4字节,2^12的范围为4页面,而不是以一个页面为准。6、深入理解图2.12,并结合图叙述线性地址到物理地址的转换。答:第一步,用32位线性地址的最高10位第31~22位作为页目录项的索引,将它乘以4,与CR3中的页目录的起始地址相加,获得相应目录项在内存的地址。第二步,从这个地址开始读取32位页目录项,取出其高20位,再给低12位补0,形成的32位就是页表在内存的起始地址。第三步,用32位线性地址中的第21~12位作为页表中页表项的索引,将它乘以4,与页表的起始地址相加,获得相应页表项在内存的地址。第四步,从这个地址开始读取32位页表项,取出其高20位,再将线性地址的第11~0位放在低12位,形成最终32位页面物理地址。第三章进程1、什么是进程控制块?它包含哪些基本信息?答:对进程进行全面描述的数据结构,Linux中把对进程的描述结构叫做task_struct:structtask_struct{}传统上这样的数据结构被叫做进程控制块PCB(processcontrolblaock)系统为了管理进程设置的一个专门的数据结构,用它来记录进程的外部特征,描述进程的运动变化过程。系统利用PCB来控制和管理进程,所以PCB是系统感知进程存在的唯一标志。进程与PCB是一一对应的。包含的基本信息:(1)状态信息-描述进程动态的变化。(2)链接信息-描述进程的父/子关系。(3)各种标识符-用简单数字对进程进行标识。(4)进程间通信信息-描述多个进程在同一任务上协作工作。(5)时间和定时器信息-描述进程在生存周期内使用CPU时间的统计、计费等信息。(6)调度信息-描述进程优先级、调度策略等信息。(7)文件系统信息-对进程使用文件情况进行记录。(8)虚拟内存信息-描述每个进程拥有的地址空间。(9)处理器环境信息-描述进程的执行环境(处理器的寄存器及堆栈等)3、Linux的进程控制块如何存放?为什么?假设ESP中存放的是栈顶指针,请用三句汇编语句描述如何获得current的PCB的地址。答:当进程一进入内核态,CPU就自动设置进程的内核栈。这个栈位于内核的数据段上,为了节省空间,Linux把内核栈和一个紧挨近的PCB的小数据结构,thread_info放在一起,占用8kb的内存区。因为这样可以节省空间,内核很容易从ESP寄存器的值获得,当前在CPU上正在运行的thread_info结构的地址。movl$0xfffe000,%eaxandl%esp,%ecxmovl%ecx,p4、PCB的组织方式有哪几种?为什么要采取这些组织方式?答:(1)进程链表(2)哈希表(3)就绪队列(4)等待队列在一个系统中,通常可以拥有数十个、数百个乃至数千个进程,相应的就有这么多PCB。为了能有效的对它们加以管理,应该用适当的方式将这些PCB组织起来。5、请编写内核模块,打印系统中各进程的名字以及PID,同时统计系统中进程的个数。答:staticintprint_pid(v