mykernel实验指导(操作系统是如何工作的)

实验要求

运行并分析一个精简的操作系统内核,理解操作系统是如何工作的

使用实验楼的虚拟机打开shell

  1. cd LinuxKernel/linux-3.9.4
  2. qemu -kernel arch/x86/boot/bzImage

然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

实验截图

首先是

然后是

之后是

要建立一个简单的时间片轮转多道程序,按照实验楼给的链接,找到了几个源代码,如图

然后按这些修改文件,并加入文件mypcb.h

再运行,0,1,2,3,之间的进程切换

分析进程的启动和进程的切换机制

mypcb.h

#define MAX_TASK_NUM 4  //定义总有4个任务/进程

#define KERNEL_STACK_SIZE 1024*8    //每个进程的堆栈大小为8KB

/*用于保有存当前进程的esp和eip*/

struct Thread {

unsigned long ip; //eip

unsigned long sp; //esp

};

/*定义进程结构体*/

typedef struct PCB {

int pid;//进程ID

volatile long state; //进程状态

char stack[KERNEL_STACK_SIZE];//进程堆栈

struct Thread thread;//保存esp、eip

unsigned long task_entry;//f进程入口

struct PCB * next;//在进程链表中指向下一个进程

struct PCB * prev;//在进程链表中指向上一个进程

}tPCB;

/*声明调度函数*/

void my_schedule(void);

mymain.c

#include "mypcb.h"

/*定义一个数组,保有存所有进程结构*/

tPCB task[MAX_TASK_NUM];

/*定义一个进程指针,指向当前正在运行的进程*/

tPCB * my_current_task = NULL;

/*是否需要调度的一个标志*/

volatile int my_need_sched = 0;

/*进程处理函数*/

void my_process(void);

/*内核入口函数*/

void __init my_start_kernel(void)

{

int pid = 0;

int i = 0;

/*初始化0号进程*/

task[pid].pid = pid;

task[pid].state = 0;

/*进程入口指向进程处理函数*/

task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;

/*指向进程栈进址*/

task[pid].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE -1];

/*进程链表中,next指向指向自己*/

task[pid].next = &task[pid];

/*创建其他进程*/

for(i=1; i< MAX_TASK_NUM; i++)

{

/*把0号进程的状态拷贝给当前进程,不同成员值再单独赋值*/

memcpy(&task[i], &task[0], sizeof(tPCB));

task[i].pid = i;

task[i].state = -1;

task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE -1];

task[i].next = task[i-1].next;

task[i-1].next = &task[i];

}

/* 运行0号进程*/

pid = 0;

/*把0号进程的地址赋给当前进程指针*/

my_current_task = &task[pid];

/*嵌入式汇编中%0,%1,%2,%3表示下面的参数,编号从0开始*/

asm volatile(

"movl %1, %%esp\n\t" /*把当前进程的栈指针赋给esp*/

"pushl %1\n\t"/*把当前进程的栈指保存到栈中*/

"pushl %0\n\t"/*保存当前进程的eip到栈中*/

"ret\n\t"/*返回操作*/

"popl %%ebp\n\t"/*弹出栈顶内容赋给ebp*/

:

: "c" (task[pid].thread.ip), "d" (task[pid].thread.sp)/*ecx=当前进程的eip, edx=当前进程的栈指针*/

);

//到此为止,0号进程就启动起来了

//end

}

void  my_process(void)

{

int i=0;

while(1)

{

i++;

if(i%100 == 0) {

printk(KERN_NOTICE "this is process %d- \n", my_current_task->pid);

/*判断是否需要切换进程,1需要切换,0不需要切换*/

if(my_need_sched == 1){

my_need_sched = 0;

/*切换进程*/

my_schedule();

}

printk(KERN_NOTICE "this is process %d +\n", my_current_task->pid);

}

}

}

myinterrupt.c

#include "mypcb.h"

/*引入外部变量*/

extern tPCB task[MAX_TASK_NUM];

extern tPCB * my_current_task;

extern volatile int my_need_sched;

volatile int time_count = 0;

/*

* 定时器中断处理函数

*/

void my_timer_handler(void)

{

/*判断是否需要切换进程*/

if(time_count % 100 == 0 && my_need_sched != 1) {

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

/*将进程切换标记为需要切换*/

my_need_sched = 1;

}

/* 计数器自加 */

time_count ++;

return;

}

/*进程高度函数*/

void my_schedule(void)

{

tPCB * next;

tPCB * prev;

/*处理异常情况,如果当前进程为空,或进程链表中的下一个进程地址为空,直接反回*/

if(my_current_task == NULL

|| my_current_task->next == NULL) {

return;

}

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

next = my_current_task->next;

prev = my_current_task;

//state:-1表示不可用,0表示正在执行,>0表示没有运行

if(next->state == 0) {

/*切换进程*/

asm volatile (

"pushl %%ebp\n\t" /*保存当前进程的ebp*/

"movl %%esp, %0\n\t" /*保存当前的栈指针到上一个进程的sp中*/

"movl %2, %%esp\n\t" /*把下一个进程的sp赋给esp*/

"movl $1f, %1\n\t" /*保存当前进程的eip到上进一个进程的ip中*/

"pushl %3\n\t" /*将下一个进程的ip压到栈中*/

"ret\n\t"/*返回*/

"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

{

/*将当前进程状态改为运行*/

next->state = 0;

/*当前进程指针指向下一下进程*/

my_current_task = next;

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

asm volatile (

"pushl %%ebp\n\t"

"movl %%esp, %0\n\t"

"movl %2, %%esp\n\t"

"movl %2, %%ebp\n\t"

"movl $1f, %1\n\t"

"pushl %3\n\t"

"ret\n\t"

"popl %%ebp\n\t"

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

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

);

}

}

 

总结部分

对“操作系统是如何工作的”理解:

首先要了解计算机工作的三个法宝:

1.存储程序计算机

所有计算机的基础性的逻辑框架。

2.函数调用堆栈

在低级语言中并不很重要,但是堆栈技术是高级语言可以运行的基础。

3.中断机制

有了中断后,就有了多道程序设计
每个程序有自己的执行流。
中断发生时,cpu把当前的eip等压入内核堆栈中,然后把eip指向中断处理程序的入口。

然后我们知道:操作系统是一管理电脑硬件与软件资源的程序,同时也是计算机系统的内核与基石。操作系统身负诸如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统是管理计算机系统的全部硬件资源包括软件资源及数据资源;控制程序运行;改善人机界面;为其它应用软件提供支持等,使计算机系统所有资源最大限度地发挥作用,为用户提供方便的、有效的、友善的服务界面。(源自百度)

操作系统是一个庞大的管理控制程序,大致包括5个方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理、文件管理。

最终可知:操作系统保存了一些队列,每个队列都是一组等待某些资源的进程。资源在操作系统中得以合理的分配以及调度,用于解决处理这些进程。

注:

姓名:林涵锦

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)的更多相关文章

  1. Linux内核分析——操作系统是如何工作的

    万子惠 + 原创作品转载请注明出处 + <Linux内核分析> 实验部分 使用实验楼的虚拟机打开shell 然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain. ...

  2. linux内核分析--操作系统是如何工作的?

    一个简单的时间片轮转多道程序 操作系统的"两把剑":中断上下文(保存现场和恢复现场)和进程上下文的切换 源代码的分析 *使用的源代码为视频中所使用的精简内核的源代码 首先分析myp ...

  3. Linux内核分析--操作系统是如何工作的

    “平安的祝福 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 一.初 ...

  4. 20135239益西拉姆 Linux内核分析 操作系统是怎样工作的?

    益西拉姆+ 原创作品+ <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 堆栈 堆栈是C语言程序运行时 ...

  5. LInux内核分析——计算机是如何工作的进行

    万子惠 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 " 实 ...

  6. linux内核分析--计算机是如何工作的

    实验部分 使用gcc -S -o main.s main.c -m32命令将源代码编译成汇编代码. 源代码如下: int g(int x) { return x + 9; } int f(int x) ...

  7. Linux内核分析— —计算机是如何工作的(20135213林涵锦)

    实验部分 (以下命令为实验楼64位Linux虚拟机环境下适用,32位Linux环境可能会稍有不同) 使用 gcc –S –o main.s main.c -m32 命令编译成汇编代码, int g(i ...

  8. Linux内核分析——计算机是如何工作的

    马悦+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.计算机是如何工作的 ( ...

  9. Linux内核分析— —构造一个简单的Linux系统MenuOS(20135213林涵锦)

    Linux内核分析— —构造一个简单的Linux系统MenuOS 实验内容 Linux内核的启动过程,从start_kernel到init进程启动 使用实验楼的虚拟机打开shell cd LinuxK ...

随机推荐

  1. httpd服务器的真实ip获取难题

    web服务器httpd中想要获取真正的ip是个难度,我们先要在配置文件中定义错误日志的格式:如下所示: 然后获取ip 上面三条输出日志中,第一条是直接访问http://172.16.213.157/i ...

  2. java.sql.SQLSyntaxErrorException: ORA-00904: "column": 标识符无效

    java.sql.SQLSyntaxErrorException: ORA-00904: "column": 标识符无效 首先查看无效的列是不是orcale关键字 , 如果不是 , ...

  3. Beta冲刺! Day3 - 砍柴

    Beta冲刺! Day3 - 砍柴 今日已完成 晨瑶:追查进度:确定推荐算法 昭锡:查看Note模块的处理逻辑.查找主页UI的解决方案 永盛:数据库的大量整合和新建,备份和还原:完成部分新的逻辑 立强 ...

  4. Address already in use: JVM_Bind问题的解决

    tomcat一般出现Address already in use: JVM_Bind的问题,可能是端口冲突,也就是端口被占用了. 这个可能是其他应用程序使用了同一个端口(默认是8080),也可能是你启 ...

  5. .whl文件打开方式 Python

    wheel文件本质上就是zip或者rar,只不过他更加方便python的安装以及使用.在之前的图片中我们只要使用pip install wheel 就可以安装wheel. 在安装了wheel之后我们可 ...

  6. Python解析器

    当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件.要运行代码,就需要Python解释器去执行.py文件. 由于整个Python语言从规范到解释器都是开源的 ...

  7. eclipse+tomcat测试连接时候HTTP Status 404错误

    想要在eclipse里部署tomcat,结果tomcat单独可以通过连接测试,用eclipse就404了 404肯定都是目录不对,试了半天在eclipse下改了一下配置和文件位置就行了 1.先在菜单栏 ...

  8. 高性能mysql之慎用BLOB与TEXT

    文章转自 https://blog.csdn.net/john1337/article/details/70919212 BLOB与TEXT是为了存储极大的字符串而设计的数据类型,采用二进制与字符串方 ...

  9. 前台返回json数据的常用方式+常用的AJAX请求后台数据方式

    我个人开发常用的如下所示: 之所以像下面这样下,一是前台Ajax,二是为安卓提供接口数据 现在常用的是返回JSON数据,XML的时代一去不复返 JSON相对于XML要轻量级的多 对JSON不是十分熟悉 ...

  10. PAT A1076 Forwards on Weibo (30 分)——图的bfs

    Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may ...