“Linux内核分析”实验二报告

张文俊 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、第二周学习内容总结

1、计算机工作“三大法宝”

首先,计算机工作原理最重要的三个内容就是:存储程序计算机工作模型、中断机制和函数调用堆栈。

存储程序计算机工作模型是计算机系统最最基础性的逻辑结构;

中断机制是多道程序操作系统的基点,没有中断机制程序只能从头一直运行结束才有可能开始运行其他程序;

函数调用堆栈是高级语言得以运行的基础,有了高级语言及函数后,堆栈成为了计算机的基础功能,函数参数传递机制和局部变量存储。

2、详细介绍函数调用堆栈

首先,堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间,即CPU内已经集成好了很多功能。

堆栈含以下元素:

函数调用框架、传递参数、保存返回地址、提供局部变量空间、C语言编译器对堆栈的使用有一套的规则。

了解堆栈存在的目的和编译器对堆栈使用的规则是理解操作系统一些关键性代码的基础。

其次,堆栈相关的寄存器常用的共有四种,esp、ebp、push、pop。详细解释如下:

esp,堆栈指针,指向栈顶;

ebp,基址指针,指向栈底,在C语言中用作记录当前函数调用基址;

push,栈顶地址减少4个字节,从低地址向高地址;

pop,栈顶地址增加4个字节,从高地址向低地址;

最后,课程介绍了函数参数的传递与框架——

(1)建立框架,即call指令

相当于

push %ebp

movl %esp,%ebp

cs:eip原来的值指向call下一条指令,该值被保存到栈顶cs:eip的值指向function的入口地址

(2)执行函数主体代码

(3)拆除框架

相当于

movl %ebp,%esp

pop %ebp

ret

函数的返回值通过eax寄存器传递

3、参数传递

这里以老师在课堂上举出的例子:

#include <stdio.h>

void p1(char c)

{

printf("%c",c);

}

int p2(int x,int y)

{

return x+y;

}

int main(void)

{

char c =‘a‘;

int x,y;

x =1;

y =2;

p1(c);

z = p2(x,y);

printf("%d = %d+%d",z,x,y);

}

首先,观察P2的堆栈框架:

这里,使用变址寻址方式,将x+y的值赋给eax。

然后,我们观察main是如何传递参数给P2的:

和main中的局部变量:

可以看到,汇编代码中用变址寻址把y的值和x的值存放到堆栈中,然后进行局部变量调用。

4、C代码中嵌入汇编代码

____asm____

(

汇编语句模板:

输入部分:

输出部分:

破坏描述部分:

);

二、实验二内容

本次实验内容是在mykernel基础上构造一个简单的操作系统内核。

首先我们cd进入LinuxKernel/linux-3.9.4文件,执行qemu -kernel arch/x86/boot/bzImage,可以看到窗口弹出如下:

然后,我们查看mymain.c和myinterrrupt.c文件:

可以发现,mymain是系统中唯一的进程,函数主要部分是my_start_kernel。每循环10万次,就打印一次my_start_kernel here.

myinterrupt是时间中断处理程序,每进行一次就会发生一次时钟处理中断,每次时钟中断都调用printk并输出。

程序分析:

mypcb.h

#define MAX_TASK_NUM 4

#define KERNEL_STACK_SIZE 1024*8

/* CPU-specific state of this task */

struct Thread {

unsigned long ip;//保存eip

unsigned long sp;//保存esp

};

typedef struct PCB{

//用于表示一个进程,定义了进程管理相关的数据结构

int pid;

volatile long state; /* 定义进程的状态:-1 不可运行, 0 可运行, >0 停止 */

char stack[KERNEL_STACK_SIZE];

//内核堆栈

struct Thread thread;

unsigned long task_entry; //指定进程入口

struct PCB *next;//进程链表

}tPCB;

void my_schedule(void);//调用了my_schedule,表示调度器

mymain.c

void my_timer_handler(void)

{

#if 1

if(time_count%1000 == 0 && my_need_sched != 1)//设置时间片的大小,时间片用完时设置一下调度标志。当时钟中断发生1000次,并且my_need_sched!=1时,把my_need_sched赋为1。当进程发现my_need_sched=1时,就会执行my_schedule。

{

printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");

my_need_sched = 1;

}

time_count ++ ;

#endif return;

}

void my_schedule(void)

{

tPCB * next; //下一个进程

tPCB * prev; //当前进程

if(my_current_task == NULL //task为空,即发生错误时返回

|| my_current_task->next == NULL)

{

return;

}

printk(KERN_NOTICE ">>>my_schedule<<<\n");

/* schedule */

next = my_current_task->next; //将当前进程的下一个进程赋给next

prev = my_current_task;//当前进程为prev

if(next->state == 0)

/* -1 unrunnable, 0 runnable, >0 stopped */

{

//在两个正在执行的进程之间做上下文切换

asm volatile( "pushl %%ebp\n\t"

/* 保存当前进程的ebp */

"movl %%esp,%0\n\t" /* 保存当前进程的esp */

"movl %2,%%esp\n\t" /* 重新记录要跳转进程的esp,将下一进程中的sp放入esp中 */

"movl $1f,%1\n\t" /* $1f指标号1:的代码在内存中存储的地址,即保存当前的eip */

"pushl %3\n\t" //将下一进程的eip压入栈,%3为 next->thread.ip

"ret\n\t" /* 记录要跳转进程的eip */

"1:\t" /* 下一个进程开始执行 */

"popl %%ebp\n\t"

: "=m" (prev->thread.sp),"=m" (prev->thread.ip)

: "m" (next->thread.sp),"m" (next->thread.ip) );

my_current_task = next;

printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);

}

else /* 与上一段代码不同的是如果下一个进程为新进程时,就运用else中的这一段代码。首先将这个进程置为运行时状态,将这个进程作为当前正在执行的进程。 */

{ next->state = 0;

my_current_task = next; printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);

/* switch to new process */

asm volatile( "pushl %%ebp\n\t" /* 保存当前进程的ebp */ "movl %%esp,%0\n\t" /* 保存当前进程的esp */ "movl %2,%%esp\n\t" /* 重新记录要跳转进程的esp */

"movl %2,%%ebp\n\t" /* 重新记录要跳转进程的ebp */ "movl $1f,%1\n\t" /* 保存当前eip */ "pushl %3\n\t" "ret\n\t" /* 重新记录要跳转进程的eip */

: "=m" (prev->thread.sp),"=m" (prev->thread.ip)

: "m" (next->thread.sp),"m" (next->thread.ip) ); }

return; }

精简内核运行结果:

三、总结

操作系统是管理计算机系统的全部硬件资源包括软件资源及数据资源;控制程序运行;改善人机界面;为其它应用软件提供支持等,使计算机系统所有资源最大限度地发挥作用,为用户提供方便有效的服务界面。

Linux是一个多进程的操作系统,所以,其他的进程必须等到正在运行的进程空闲CPU后才能运行。

当正在运行的进程等待其他的系统资源时,Linux内核将取得CPU的控制权,并将CPU分配给其他正在等待的进程,这就是进程切换。

内核中的调度算法决定将CPU分配给哪一个进程。

进程是动态执行的实体,内核是进程的管理者。

进程不但包括程序的指令和数据,而且包括程序计数器和CPU的所有寄存器以及存储临时数据的进程堆栈。

所以,正在执行的进程包括处理器当前的一切活动。

进程既可以在用户态下运行,也能在内核下运行,只是内核提供了一些用户态没有的核心服务,

因此进程在访问这些服务时会产生中断,必须进行用户态与内核态的切换。

时间: 2024-08-02 15:09:55

“Linux内核分析”实验二报告的相关文章

“Linux内核分析”实验三报告

构造一个简单的Linux系统 张文俊+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验内容: 一.gdb跟踪调试内核从start_kernel到init进程启动 1.qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明: // -S freeze CPU at s

【MOOC EXP】Linux内核分析实验七报告

程涵  原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 可执行程序的装载 知识点梳理 一.预处理.编译.链接和目标文件的格式 可执行程序是如何得来的 C源代码(.c)经过编译器预处理被编译成汇编代码(.asm) 汇编代码由汇编器被编译成目标代码(.o) 将目标代码链接成可执行文件(a.out) 可执行文件由操作系统加载到内存中执行 vi hello.c gcc -E -o hello.cpp hell

【MOOC EXP】Linux内核分析实验八报告

知识点梳理 一.进程切换的关键代码分析 1.1 进程调度与进程调度的时机分析 操作系统原理中介绍了大量进程调度算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已. 对于理解操作系统的工作机制,反而是进程的调度时机与进程的切换机制更为关键. 不同类型的进程有不同的调度需求 第一种分类: I/O-bound 频繁的进行I/O:通常会花费很多时间等待I/O操作的完成 CPU-bound 计算密集型:需要大量的CPU时间进行运算 第二种分类: 批处理进程 实时

Linux内核分析实验二:mykernel实验指导(操作系统是如何工作的)

计算机是如何工作的?(总结)——三个法宝 存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: 函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语言的时候堆栈机制对于计算机来说并不那么重要,但有了高级语言及函数,堆栈成为了计算机的基础功能: enter pushl %ebp movl %esp,%ebp leave movl %ebp,%esp popl %ebp 函数参数传递机制和局部变量存储 中断,多道程序操作系统的基点,没有中断机制程序只能从头一直运行结束才有可能开始运行其他程

“Linux内核分析”实验一

"Linux内核分析"实验一 作者:何振豪 原创作品转载请注明出处 http://www.cnblogs.com/scoyer/p/6411414.html <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 计算机由硬件和软件组成,硬件主要是CPU和内存,软件是系统软件和应用软件.最开始的计算机是由冯诺依曼提出的存储程序的思路开始的,这就对应硬件的CPU和内存,CPU执行指令,指令和相关数据

Linux内核分析(二)----内核模块简介|简单内核模块实现

Linux内核分析(二) 昨天我们开始了内核的分析,网上有很多人是用用源码直接分析,这样造成的问题是,大家觉得很枯燥很难理解,从某种意义上来说linux系统本身就是由一个个模块构成的,所以我会结合内核模块的设计,去分析内核,从而达到对linux内核的理解. 今天我们会分析到以下内容: 1.      Linux内核模块简介 2.      简单内核模块实现 l  Linux内核模块简介 1.       何为内核模块 在上一篇博文中我们先通过内核配置,在配置的过程中我们对内核的组件进行了选择(当

Linux内核分析第一次学习报告

Linux内核分析第一次学习报告 学生 黎静 学习内容 1.存储程序计算机工作模型 冯诺依曼体系结构:核心思想为存储程序计算机. CPU抽象为for循环,总是执行下一条指令,内存保存指令和数据,CPU来解释和执行这些指令. API:应用程序编程接口(程序员与计算机的接口界面) ABI:二进制接口,指令编码(程序员与CPU的接口界面) 2.X86汇编 1.寄存器 (1)通用寄存器 (2)段寄存器: (3)标志寄存器 2.计算机的汇编指令 (1)movl指令: 寄存器寻址,寄存器模式,以%开头的寄存

“Linux内核分析”实验报告

Linux内核分析:实验一 潘俊洋 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机体系结构与程序运行过程 现代计算机大都采用的是“冯.诺依曼”体系结构,它的核心思想是:程序存储,指令和数据不加区分的放在一个存储器中.由指令指针寄存器保存着下一条将要执行指令的地址,这个寄存器在32位系统中叫eip,64位系统中叫rip. 指令是用二进制编码的,难于记忆.为了更有效的编写程序,人们就

“Linux内核分析”实验报告8

路过的小游侠+ 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度和进程调度时机的分析:不同类型的进程有不同的调度需求,所以需要不同的算法来满足人的需求和使计算机高效运行.就有了调度策略,Linux根据优先级排队 - schedule ,内核函数,非系统代用,只能使用中断处理过程调用(时钟中断,i/o中断,系统调用和异常),或者