解析Linux内核

合集下载

linux内核堆栈解析方法

linux内核堆栈解析方法

在 Linux 系统中,内核堆栈(kernel stack)用于执行内核代码。

当发生操作系统内核崩溃、内核出现异常或需要调试时,理解和分析内核堆栈十分重要。

以下是分析 Linux 内核堆栈的常用方法:使用dmesg:当内核发生故障时,错误信息和堆栈追踪通常会输出到内核日志。

你可以使用 dmesg 命令查看内核日志中的堆栈追踪。

dmesg | grep -i stack操作系统崩溃时的系统日志:有时通过分析内核崩溃时的系统日志(如/var/log/syslog 或/var/log/messages、/var/log/kern.log)也可以找到有关堆栈信息。

使用 dump_stack() 函数:在内核代码中,你可以使用 dump_stack() 函数打印当前线程的堆栈信息。

这在调试内核代码时非常有用。

系统核心转储(Core Dump):内核崩溃时,操作系统有时会生成系统核心转储文件。

你可以使用 GNU Debugger(GDB)来分析内核转储文件。

首先,安装 Linux 的调试符号表(debugging symbols),然后使用 gdb 命令加载符号表和内核转储文件,最后使用 bt(backtrace)命令查看堆栈追踪。

gdb path/to/vmlinux path/to/core_dump(gdb) bt请注意,要使内核生成核心转储文件,需要正确配置内核。

具体配置方法取决于你所使用的 Linux 发行版。

内核调试器(如 KGDB 和 KDB):如果你正在研究内核问题,可以使用内核调试器 KGDB 或 KDB。

KGDB 是基于 GDB 的内核调试器,可以在源代码级别进行调试。

KDB 则是一个基于文本的内核调试器。

使用这些工具,你可以从内核级别设置断点、单步执行代码、检查内存内容和调用堆栈等。

通过以上方法可以帮助你分析 Linux 内核堆栈。

如何选择最佳方法取决于你的具体需求和问题。

在进行内核调试之前,请确保熟悉 Linux 操作系统和内核开发的基本知识。

linux内核kallsyms机制分析

linux内核kallsyms机制分析

linux内核kallsyms机制分析2016-07-24 15:59:41分类: LINUX原文地址:linux内核kallsyms机制分析作者:wangbaolin7191.一、前言2.Linux内核是一个整体结构,而模块是插入到内核中的插件。

尽管内核不是一个可安装模块,但为了方便起见,Linux把内核也看作一个模块。

那么模块与模块之间如何进行交互呢,一种常用的方法就是共享变量和函数。

但并不是模块中的每个变量和函数都能被共享,内核只把各个模块中主要的变量和函数放在一个特定的区段,这些变量和函数就统称为符号。

3.4.因此,内核也有一个module结构,叫做kernel_module。

另外,从kernel_module开始,所有已安装模块的module结构都链在一起成为一条链,内核中的全局变量module_list就指向这条链:5.struct module *module_list =&kernel_module;6.7.一般来说,内核只会导出由EXPORT_PARM宏指定的符号给模块使用。

为了使debugger提供更好的调试功能,需要使用kallsyms 工具为内核生成__kallsyms段数据,该段描述所有不处在堆栈上的内核符号。

这样debugger就能更好地解析内核符号,而不仅仅是内核指定导出的符号。

8.9.二、简介10.在v2.6.0 的内核中,为了更好地调试内核,引入新的功能kallsyms.kallsyms把内核用到的所有函数地址和名称连接进内核文件,当内核启动后,同时加载到内存中.当发生oops,例如在内核中访问空地址时,内核就会解析eip位于哪个函数中,并打印出形如:11.EIP is at cleanup_module+0xb/0x1d [client]的信息,12.调用栈也用可读的方式显示出来.13.Call Trace:14.[<c013096d>] sys_delete_module+0x191/0x1ce15.[<c02dd30a>] do_page_fault+0x189/0x51d16.[<c0102bc1>] syscall_call+0x7/0xb17.18.当然功能不仅仅于此,还可以查找某个函数例如的sys_fork 的地址,然后hook它,kprobe就是这么干的。

linux操作系统的基本原理

linux操作系统的基本原理

linux操作系统的基本原理
Linux操作系统是一种开源的自由操作系统,其基本原理包括以下几个方面:
1. 内核:Linux操作系统的核心是内核,它是操作系统的核心模块,控制着系统的所有硬件和软件资源。

内核具有多任务处理、进程管理、文件系统管理、设备管理、内存管理等功能。

2. 虚拟文件系统:Linux操作系统使用虚拟文件系统(VFS)作为文件系统的框架。

VFS为所有文件系统提供了一个通用的接口,使得文件系统可以互相转换。

3. Shell:Linux操作系统使用的命令行接口被称为Shell。

Shell是用户与内核交互的一种方式,用户可以通过Shell来执行命令、管理文件、创建进程等。

4. 程序库:Linux操作系统提供了一系列的程序库,如C库、X库等,这些程序库提供了一些基本的函数和工具,方便程序员开发应用程序。

5. 系统调用:Linux操作系统提供了大量的系统调用,它们是用户程序和内核之间的接口。

用户程序可以通过系统调用来访问内核提供的各种服务,如读写文件、创建进程、网络通信等。

Linux操作系统的基本原理为开发者和用户提供了一个稳定、高效、灵活的操作系统。

它的开源特性使得用户可以自由地修改和定制操作系统,满足不同需求。

- 1 -。

linux内核进程cpu调度基本原理

linux内核进程cpu调度基本原理

linux内核进程cpu调度基本原理Linux内核的CPU调度基本原理是通过多任务处理,将CPU 时间片分配给不同的进程或线程来实现。

1. 调度策略:Linux内核支持多种调度策略,包括先来先服务(FCFS)、时间片轮转、优先级调度等。

默认的调度策略是时间片轮转调度策略,即每个进程被分配一个时间片,在时间片用完之后,将CPU切换到下一个就绪状态的进程上。

2. 就绪队列:内核会维护一个就绪队列,存放所有准备好运行但还未分配CPU时间的进程。

根据进程的优先级和调度策略,内核会从就绪队列中选择一个合适的进程来执行。

3. 进程优先级:每个进程都有一个优先级值,表示其重要性和紧急程度。

较高优先级的进程在调度时会获得更多的CPU时间。

Linux内核使用动态优先级调度策略,根据进程的历史行为和资源使用情况动态调整进程的优先级。

4. 时间片和抢占:时间片是CPU分配给进程的最小单位,当一个进程的时间片用完后,如果它还未完成,内核会将其置于就绪队列末尾,并将CPU分配给下一个就绪进程。

此外,Linux 内核支持抢占式调度,即当一个优先级更高的进程出现时,可立
即抢占当前运行的进程,将CPU资源分配给新的进程。

5. 实时进程:除了普通进程,Linux内核还支持实时进程。

实时进程具有更高的优先级和较小的延迟要求,它们得到更快的响应时间。

实时进程的调度算法相对于普通进程更加严格,以满足实时性要求。

Linux内核的CPU调度基本原理是通过就绪队列、进程优先级和时间片轮转等策略,将CPU时间动态地分配给不同的进程或线程,以完成多任务处理。

linux系统的内核子系统之间的关系

linux系统的内核子系统之间的关系

linux系统的内核子系统之间的关系Linux系统的内核子系统之间的关系Linux操作系统的内核是其最核心的组成部分,它负责管理和控制整个系统的运行。

内核由多个子系统组成,每个子系统负责不同的功能模块,它们之间相互配合,共同完成系统的各项任务。

本文将介绍几个常见的内核子系统及其之间的关系。

1. 文件系统子系统文件系统子系统负责管理文件和目录的存储和访问。

它提供了对文件系统的抽象,使用户和应用程序可以通过文件路径来访问文件和目录。

文件系统子系统由虚拟文件系统层、各种具体的文件系统类型和存储设备驱动程序组成。

虚拟文件系统层提供了一个统一的接口,使不同的文件系统可以以相同的方式进行访问。

具体的文件系统类型如ext4、NTFS等负责实现不同的文件系统格式,而存储设备驱动程序则负责控制硬盘、闪存等存储设备的读写。

2. 进程管理子系统进程管理子系统负责管理系统中的进程。

它负责创建、终止和调度进程,并提供进程间通信和同步的机制。

进程管理子系统包括进程调度器、进程控制块、进程间通信和同步机制等。

进程调度器决定了系统中运行哪些进程以及它们的优先级和时间片分配。

进程控制块保存了进程的状态信息,包括程序计数器、寄存器和运行时堆栈等。

进程间通信和同步机制如管道、信号量、消息队列等,使不同进程之间可以进行数据交换和协调工作。

3. 设备驱动子系统设备驱动子系统负责管理和控制硬件设备的访问。

它提供了对设备的抽象接口,使应用程序可以通过统一的方式访问不同类型的设备。

设备驱动子系统包括字符设备驱动和块设备驱动。

字符设备驱动用于管理字符设备,如串口、键盘等,它提供了以字节为单位的读写接口。

块设备驱动用于管理块设备,如硬盘、闪存等,它提供了以块为单位的读写接口。

设备驱动子系统还包括中断处理、DMA控制等功能,用于处理设备的中断请求和数据传输。

4. 网络子系统网络子系统负责管理和控制系统的网络功能。

它提供了网络协议栈、网络接口和网络设备驱动等功能。

linux内核分析课后答案

linux内核分析课后答案

linux内核分析课后答案Linux是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。

支持模块的动态装卸(裁剪)。

Linux内核就是基于这个策略实现的。

Linux进程1.采用层次结构,每个进程都依赖于一个父进程。

内核启动init程序作为第一个进程。

该进程负责进一步的系统初始化操作。

init进程是进程树的根,所有的进程都直接或者间接起源于该进程。

从技术层面讲,内核是硬件与软件之间的一个中间层。

作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。

从应用程序的层面讲,应用程序与硬件没有联系,只与内核有联系,内核是应用程序知道的层次中的最底层。

在实际工作中内核抽象了相关细节。

内核是一个资源管理程序。

负责将可用的共享资源(CPU时间、磁盘空间、网络连接等)分配得到各个系统进程。

内核就像一个库,提供了一组面向系统的命令。

系统调用对于应用程序来说,就像调用普通函数一样。

Linux 内核可以进一步划分成 3 层。

最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。

系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。

这些代码是 Linux 所支持的所有处理器体系结构所通用的。

在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board SupportPackage)的部分。

这些代码用作给定体系结构的处理器和特定于平台的代码。

Linux 内核实现了很多重要的体系结构属性。

在或高或低的层次上,内核被划分为多个子系统。

Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。

这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。

每种内核都有自己的优点,不过这里并不对此进行讨论。

随着时间的流逝,Linux 内核在内存和 CPU 使用方面具有较高的效率,并且非常稳定。

linux内核中的workqueue_和work_使用方法__示例及解释说明

linux内核中的workqueue_和work_使用方法__示例及解释说明

linux内核中的workqueue 和work 使用方法示例及解释说明1. 引言1.1 概述Linux内核是操作系统的核心,工作队列(workqueue)和work是其重要的组成部分。

工作队列提供了一种异步机制,用于处理长时间运行的任务或者需要在后台执行的任务。

而work则是具体的任务对象,通过将任务封装为work对象,可以方便地在工作队列中进行调度和管理。

1.2 文章结构本文将详细介绍Linux内核中的工作队列(workqueue)和work的使用方法,并通过示例和解释说明来展示其具体应用。

文章分为五个部分:引言、Workqueue和Work基础知识、Workqueue使用方法、Work使用方法和示例说明以及结论与展望。

1.3 目的本文旨在帮助读者全面了解Linux内核中工作队列和work的概念以及它们的使用方法。

通过深入解析其原理和实践案例,读者可以掌握如何利用工作队列和work来进行高效地后台任务处理,并为未来的研究和应用提供思路和参考。

2. Workqueue和Work基础知识:2.1 Workqueue介绍:Workqueue是Linux内核中的一种机制,用于管理和执行工作任务。

它是一种异步处理的机制,可以在后台处理一些耗时的操作,而不会阻塞系统或其他任务的执行。

2.2 Work介绍:Work是由Workqueue管理的工作任务。

每个Work代表一个需要在后台执行的具体工作。

一个Work可以被认为是一段代码,在特定条件或事件发生时被调用执行。

2.3 Work之间的关系:Workqueue可以创建和管理多个Work任务。

当某个条件满足时,例如硬件中断发生或定时器超时,Workqueue会从任务队列中选择一个可用的Work,并将其分配给空闲的内核线程来运行,以完成相应的工作。

在这个过程中,多个Work之间不存在直接依赖关系。

每个Work都是独立地被分配、执行和管理。

它们并行运行,并且不需要等待其他Work的完成。

linux内核zImage详解

linux内核zImage详解

linux内核zImage详解以下内容基于s5pv210进⾏分析 zImage由head.o,piggy.gzip.o,misc等链接组成,piggy.gzip.o中包含压缩的内核镜像,zImage的作⽤实际上就是对内核进⾏解码。

zImage还是位置⽆关码,它的链接地址为0,可以在任何地址运⾏,因为在对其源⽂件进⾏编译时编译器参数设置了-fpic,通过反汇编看到编译⽣成了.got和.got.plt段。

.dot.plt为空,查看反汇编得知编译器对c语⾔函数的调⽤是通过bl指令实现的,所以c的函数调⽤是位置⽆关码;⽽对于c中全局变量的处理是通过相对寻址找到全局变量⼀⼀对应的.got地址(这⾥的相对寻址是:在每个函数段中如果使⽤了全局变量都会存放.got⾸地址相对运⾏pc的偏移量以及全局变量在.got中的偏移),所以⽆论运⾏地址和链接地址匹不匹配,代码都能正确找到全局变量的.got地址。

.got地址中存放了全局变量的链接地址,所以只要在zImage的初始化c语⾔运⾏环境部分增加对.got部分全局变量的重定位则代码将正确运⾏,因此zImage成为了位置⽆关码 现在开始分析arch/arm/boot/compressed/head.s进⾏代码分析:start:.type start,#function //⽤于指定标号start为函数.rept 8 //指定.endr以前的指令循环8次mov r0, r0.endrb 1f.word 0x016f2818 @魔数⽤于表⽰zImage的⾝份.word start @ zImage的链接地址.word _edata @ zImage的链接结束地址1: mov r7, r1 @ save architecture IDmov r8, r2 @ save atags pointer #ifndef __ARM_ARCH_2__/*⽤于判断是不是angel启动,我们是u-boot启动进来时已经是svc模式了所以直接跳到not_angel */mrs r2, cpsr @ get current modetst r2, #3 @ not user?bne not_angelmov r0, #0x17 @ angel_SWIreason_EnterSVCARM( swi 0x123456 ) @ angel_SWI_ARMTHUMB( svc 0xab ) @ angel_SWI_THUMBnot_angel:mrs r2, cpsr @ turn off interrupts toorr r2, r2, #0xc0 @ prevent angel from runningmsr cpsr_c, r2#elseteqp pc, #0x0c000003 @ turn off interrupts#endif.textadr r0, LC0 //将LC0的运⾏地址加载到r0,ARM( ldmia r0, {r1, r2, r3, r4, r5, r6, r11, ip, sp})/*将r0指定的地址中的数据依次加载到括号⾥的寄存器中:r1 : LC0的链接地址r2 : BSS 起始链接地址r3 : BSS 结束链接地址r4 :内核的链接地址r5 : zImage的链接地址r6 :内核的⼤⼩r11 :.got的起始链接地址,ip :.got的结束链接地址sp :链接下的栈顶r0 : LC0的运⾏运⾏地址*/THUMB( ldmia r0, {r1, r2, r3, r4, r5, r6, r11, ip} ) //⽆效THUMB( ldr sp, [r0, #32] ) //⽆效subs r0, r0, r1 //r0成为运⾏地址与链接地址的偏移量beq not_relocated //运⾏地址与连接地址相同跳转该语句add r5, r5, r0 //r5 : zImage的运⾏地址add r11, r11, r0 //r11:.got的起始运⾏地址add ip, ip, r0 //ip:.got的结束运⾏地址#ifndef CONFIG_ZBOOT_ROMadd r2, r2, r0 //r2 :bss的运⾏起始地址add r3, r3, r0 //r3:bss的运⾏结束地址add sp, sp, r0 //sp:运⾏的栈顶地址/** 将.got中全局变量的链接地址重定位为运⾏地址*/1: ldr r1, [r11, #0] @ relocate entries in the GOTadd r1, r1, r0 @ table. This fixes up thestr r1, [r11], #4 @ C references.cmp r11, ipblo 1b#else/*未编译*/1: ldr r1, [r11, #0] @ relocate entries in the GOTcmp r1, r2 @ entry < bss_start ||cmphs r3, r1 @ _end < entryaddlo r1, r1, r0 @ table. This fixes up thestr r1, [r11], #4 @ C references.cmp r11, ipblo 1b#endifnot_relocated: mov r0, #01: str r0, [r2], #4 @ clear bssstr r0, [r2], #4str r0, [r2], #4str r0, [r2], #4cmp r2, r3blo 1bbl cache_onmov r1, sp //r1 :运⾏的栈顶地址add r2, sp, #0x10000 //r2:堆结束地址64k/*堆的结束地址⼤于内核的起始地址或者内核的结束地址⼤于zImage的运⾏起始地址将发⽣覆盖,我们这边会发⽣覆盖所以不跳转继续往下执⾏*/ cmp r4, r2bhs wont_overwriteadd r0, r4, r6cmp r0, r5bls wont_overwrite/*r0:堆结束的地址r1:堆起始的地址r2:堆结束的地址r3:机器ID*/mov r5, r2 @ decompress after malloc spacemov r0, r5mov r3, r7bl decompress_kernel 这⾥看看 decompress_kernel中的传⼊参数unsigned long decompress_kernel(unsigned long output_start, //r0 解压内核输出地址unsigned long free_mem_ptr_p,//r1 堆起始地址unsigned long free_mem_ptr_end_p,//r2 堆结束地址int arch_id//r3 机器ID)解压后返回到head中继续执⾏add r0, r0, #127 + 128 @ alignment + stackbic r0, r0, #127 @ align the kernel length分析如下:r0为decompress_kernel()函数的返回值,它的返回值最终为Linux内核解压后的长度,这⾥的第⼀条指令完成的功能是在解压后的Linux内核后⾯预留128字节的栈空间,第⼆条指令使最终r0的值为128字节对齐此时我们的内存空间分布如下:| || || ||----------------|----| 128byte | || | || + | || | r0| 解压后的内核 | || | || | ||----------------|<-------r5| 堆64k ||----------------|| 栈4k ||----------------|| || 压缩的内核 || 当前运⾏的代码|| ||----------------|0x30008000 zImage的加载地址| |---------------------/** r0 = decompressed kernel length* r1-r3 = unused* r4 = kernel execution address* r5 = decompressed kernel start* r7 = architecture ID* r8 = atags pointer* r9-r12,r14 = corrupted*/add r1, r5, r0 @ end of decompressed kerneladr r2, reloc_startldr r3, LC1add r3, r2, r31: ldmia r2!, {r9 - r12, r14} @ copy relocation codestmia r1!, {r9 - r12, r14}ldmia r2!, {r9 - r12, r14}stmia r1!, {r9 - r12, r14}cmp r2, r3blo 1bmov sp, r1add sp, sp, #128 @ relocate the stackbl cache_clean_flushARM( add pc, r5, r0 ) @ call relocation codeTHUMB( add r12, r5, r0 )THUMB( mov pc, r12 ) @ call relocation code解析如下:r1 = r5 + r0 = 解压后内核存放的地址 + 内核⼤⼩r2 = 当前reloc_start标签所在的地址r3 = *LC1LC1: .word reloc_end - reloc_start所以r3 为重定位代码段的⼤⼩r3 = r2 + r3 =重定位代码段的结束地址接下来的指令就是将重定位的代码段搬移到解压的Linux内核后⾯并且重定义了栈最后跳转重定义代码| ||----------------|<---sp| 128byte ||----------------|<---r1| || 重定位代码段 || ||----------------|<---pc| 128byte | || | || + | || | r0| 解压后的内核 | || | || | ||----------------|------->r5| 堆64k ||----------------|| 栈4k ||----------------|| || 压缩的内核 || 当前运⾏的代码|| ||----------------|0x30008000 zImage的加载地址| |---------------------/ * r0 = decompressed kernel length* r1-r3 = unused* r4 = kernel execution address* r5 = decompressed kernel start* r7 = architecture ID* r8 = atags pointer* r9-r12,r14 = corrupted*/.align 5reloc_start: add r9, r5, r0 //内核的结束地址sub r9, r9, #128 //减掉栈部分debug_reloc_startmov r1, r41:.rept 4ldmia r5!, {r0, r2, r3, r10 - r12, r14} //⼀次copy28个字stmia r1!, {r0, r2, r3, r10 - r12, r14}.endrcmp r5, r9blo 1bmov sp, r1add sp, sp, #128 @ relocate the stackdebug_reloc_endcall_kernel: bl cache_clean_flushbl cache_offmov r0, #0 @ must be zeromov r1, r7 @ restore architecture numbermov r2, r8 @ restore atags pointermov pc, r4 @ call kernel 以上就是zImage的启动过程,接下来将跳转内核。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

解析Linux内核
目录
一、编译内核 (2)
二、编译内核 (8)
1、进程控制 (8)
2、实验5(内核共享空间的调用) (10)
3、实验5(一个读者一个书写者共享一个空间传递信息).. 11
4、实验5(多个读者多一个书写者共享一个空间) (14)
5、实验6(中断)的共享空间 (15)
6、在内核内添加模块 (15)
解析Linux内核(2013.7.22):
时钟--系统--时钟-多任务都需要初始化
一、编译内核
1、要编译一个新的内核首先要把内核安装包放在/usr/src目录下并进行解压和运行如图1所示:
图1
2、在make menuconfig 编译后会出现图选择要第三个进去,然后里面含有全部的X86的都要选上,如图2、
3、4所示:
图2
图3
图4
3、做好图1后接着进行图5的编译:
图5 4、编译了图5后再进行图6的操作:
图6 5、基本流程指令如图7所示:
图7
6、有时候出现问题,可以查查网上资料,如果生成磁盘太小,就修改磁盘就可以了。

做法可以参照makefs或者图8所示:
图8
7、在弄好了上面之后就可以更改部分内核了,我们可以把自己的调用文件加上去。

在linux 内核安装包下面如图9路径下的/usr/include/asm下更改unist_32.h文件添加语句如图10,指令如图11所示:
图9 更改文件位置
图10 添加文件流程
图11 更改文件指令汇总
8、在linux的kernel/sys.c下增加一段小程序具体路径如图12,指令如图13,程序如图14所示:
图12 添加程序文件位置
图13添加程序指令
图14 添加程序
9、弄好了上面步骤后就可以输入指令(make)重新编译内核了,当make结束后输入指令(make install),然后重启。

10、最后可以通过写程序来验证我们写的是否已经可以使用如面16所示但用到的地址在如图15所示,指令如图17所示:
图15 添加语句位置
图16 程序验证
图17 验证指令汇合
用gcc编译源程序
# gcc –o test test.c
运行程序
# ./test
输出结果
em…, this is my uid:0
12、软中断处于后半部分可以让程序退后处理。

二、编译内核
1、进程控制
在进程控制里面可以用指令查我们虚拟机的运行情况如图1、2、3、4、5、6所示:
图1 PS指令查询进程
图2 查询虚拟机进程指令图
图3 查询虚拟机cpu进程
图4 查询
图5进程流程控制(部分)
图6 控制进程流程图切换2、文件中的实验5(内核共享空间的调用)
共享空间流程图如图7所示:
图7 共享空间调用
在复制实验5的代码过去的时候还需要在文件的顶部加上两个包含文件才能成功编译如图8所示:
图8 shm_sample.c所需添加的头文件
在虚拟机上共享空间的指令操作如图9所示:
图9 共享空间中的指令操作
3、文件中的实验5(一个读者一个书写者共享一个空间传递信息)
共享空间流程图写入如图10,共享空间传递信息的读取如图10.1所示:
图10 共享空间进程中的写入流程
图10.1 共享空间进程控制的读取流程图
在进行程序复制后,会发现出现一个错误是因为有个值没有进行类型的强制转换原图如图11所示,修改图如图12所示:
图11 原程序未强制转换地点
图12 进行强制转换的地方
编写好了程序后就指令操作如图13所示,输入后就自动进入了读者面板,进入后原终端部关闭而开启另一个新的终端进入写者面板,然后书写信息就可以传输到读者面板中如图14所示:
图13 指令操作及读者面板
图14 写者和读者共享空间面板
4、文件中的实验5(多个读者多一个书写者共享一个空间)
共享空间流程图如图 15所示:
图15 1writer多reader共享空间的进程控制流程图
在传输的时候通过1个writer传输只能先传到刚刚开辟的第一个reader的面板,传输的第二个就到第二个reader面板上,传输第三个就到第三个的reader面板上,有多少个就通过一个个间隔着传输内容,就像排队炒菜吃饭一样,一个人炒的菜就是第一次服务员下单给直接的东西(相当于writer第一次传输的内容),第二个就等到服务员(writer)下单然后就可以根据下的单炒单上的菜(这个菜就是writer上传到共享空间的内容),每个人来炒菜都需要排队而且要等服务员(writer)下单,然后才可以吃到(得到)单上的菜(writer 输入的内容)一次反复,具体实例可如图16所示:
图16 1writer多reader的进程控制视图
5、文件中的实验6(中断)的共享空间
流程图如图 17所示:
6、在内核内添加模块
在内核中可以添加自己所需的模块具体操作可以参照图18所示:
图18 内核模块文件路径
在makefile中可以对我们的文件生成.KO文件,而README文件只是对我们文件的说明,没其他作用,makefile中的说明如图19所示:
图19 makefile文件的说明
对内核添加模块的指令可以如图20.1、图20.2、图20.3所示:
图20.1 内核模块添加指令及解说
图20.2 内核模块添加指令及解说
图20.3 内核模块添加指令及解说
在设备手册(1)里面也可以查到基本的操作指令如图20.4所示:
图20。

4 添加内核模块操作的基本指令
7、内核模块在/proc文件系统中应用
在内核中添加文件模块,并且在文件中可以调用的参考如图21所示:
图21 添加内核模块到/proc文件系统中
移除在/proc文件系统中移除内核模块需要到原来放的文件内对内核文件进行rmmod xxx.ko文件就可以在文件系统中移除了如图22所示。

图22 移除在文件系统内的内核模块
关于/proc文件夹的内容和作用可参考如图23所示:
图23 /proc目录简介
8、内核链表
链表的操作要求如图24所示:
图24
链表的指令操作如图25,更改makefile如图26,链表最后结果如图27所示:
图25 链表操作指令
图26 makefile更改
图27 链表最后结果显示
9、统计操作系统缺页次数
实验统计自内核加载完成以后到当前时刻为止发生的缺页次数和经历过的时间;第二个实验统计从当前时刻起一段时间内发生的缺页中断次数
1、如果要统计系统操作次数需要用到新定义的函数,如此就要进行内核的编写,修改于增加的东西先在include/linux/mm.h文件中声明变量pfcount:如图28.1所示:
图28.1增加的内容
2、在archx86/mm/fault.c文件中定义变量pfcount如图28.2所示:
图28.2 添加的内容
3、每次产生缺页中断,并且确认是由缺页引起的,则将变量值递增1。

这个操作在do_page_fault()函数中执行如图28.3所示:
图28.3 增加的内容
4、在/kernel/time.c文件中加入EXPORT_SYMBOL(pfcount),让内核模块能够读取变量pfcount;同理,内核模块也可以读取jiffies如图28.4所示:
图28.4 增加的内容
这样就可以通过作为中介的/proc文件系统,轻松地读取我们所需要的两个变量的值了。

使用命令cat /proc/pf/pfcount /proc/pf/jiffies,就可以在终端打印出至今为止的缺页次数和已经经历过的jiffies数目。

隔几分钟再使用命令cat /proc/pf/pfcount /proc/pf/jiffies,查看一下打印出的缺页次数和jiffies数目。

比较一下结果。

参照图28.5所示:
图28.5 编译成功后操作指令查看
9、简单设备字符设备实验
图29.1设置一个设备号
图29.2当设置的设备地址被占用可修改别的地点
图29.3查看设备地点
图29.4修改与结点相连接地方
图29.5修改连接结点文件地方
图29.6 如何删除结点
图29.7 基本指令操作。

相关文档
最新文档