一、知识要点

1.计算机是如何工作的?(总结)——三个法宝

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

  • 函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语言的时候堆栈机制对于计算机来说并不那么重要,但有了高级语言及函数,堆栈成为了计算机的基础功能;

    • enter

      • pushl %ebp

      • movl %esp,%ebp

    • leave

      • movl %ebp,%esp

      • popl %ebp

    • 函数参数传递机制和局部变量存储

    • 了解堆栈存在的目的和编译器对堆栈使用的规则是理解操作系统一些关键性代码的基础
  • 中断,多道程序操作系统的基点,没有中断机制程序只能从头一直运行结束才有可能开始运行其他程序。

2.堆栈寄存器和堆栈操作

  • 堆栈相关的寄存器:esp 堆栈指针、ebp 基址指针
  • 堆栈操作:

-push 栈顶地址减少4个字节

-pop   栈顶地址增加4个字节

  • 其他关键寄存器

3.有压栈必有出栈,函数的返回值用eax寄存器传递

4.中断实现了多道程序设计,再各个程序的执行流之间来回切换,CPU将程序的ebp压入栈,并指向一个中断处理程序,从而由CPU和内核代码共同实现了保存现场和恢复现场

5.C代码中嵌入汇编代码的写法:

__asm__(
汇编语句模板:
输入部分:
输出部分:
破坏描述部分:);

6.操作系统的两把剑:中断上下文和进程上下文的切换

 

二、实验

1.实验内容

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

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

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

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

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

使用自己的Linux系统环境搭建过程参见mykernel,其中也可以找到一个简单的时间片轮转多道程序内核代码

2.实验截图

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

使用自己的Linux系统环境搭建过程参见mykernel,其中也可以找到一个简单的时间片轮转多道程序内核代码

返回之后再次运行,可看到0、1、2、3几个进程相互切换。

3.源代码分析

mypcb.h

这个代码的目的是定义一个进程控制块(PCB)。

/*
*  linux/mykernel/mypcb.h
*
*  Kernel internal PCB types
*
*  Copyright (C) 2013  Mengning
*
*/#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 unrunnable, 0 runnable, >0 stopped */ char stack[KERNEL_STACK_SIZE]; /* CPU-specific state of this task */ struct Thread thread; unsigned long task_entry; struct PCB *next; }tPCB; void my_schedule(void);//调用了my_schedule,表示调度器

mymain.c

/*
*  linux/mykernel/mymain.c
*
*  Kernel internal my_start_kernel
*
*  Copyright (C) 2013  Mengning
*
*/
#include <linux/types.h>
#include <linux/string.h> #include <linux/ctype.h> #include <linux/tty.h> #include <linux/vmalloc.h> #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;//初始化一个进程0 int i; /* Initialize process 0*/ task[pid].pid = pid; task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */ task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process; //定义进程0的入口为my_process task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1]; task[pid].next = &task[pid]; //因为一开始系统里只有进程0,所以这一行代码表示的是pid的next还是指向自己 /*fork more process */ //创建更多其他的进程,在初始化这些进程的时候可以直接拷贝0号进程的代码 for(i=1;i<MAX_TASK_NUM;i++) { 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]; } /* start process 0 by task[0] */ pid = 0; my_current_task = &task[pid]; asm volatile( "movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */ "pushl %1\n\t" /* push ebp */ "pushl %0\n\t" /* push task[pid].thread.ip */ "ret\n\t" /* pop task[pid].thread.ip to eip */ "popl %%ebp\n\t" : : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/ ); } /* %0表示参数thread.ip,%1表示参数thread.sp。 movl %1,%%esp表示把参数thread.sp放到esp中; 接下来push %1,又因为当前栈为空,esp=ebp,所以等价于push ebp; 然后push thread.ip;ret等价于pop thread.ip;最后pop ebp */ void my_process(void)//定义所有进程的工作,if语句表示循环1000万次才有机会判断是否需要调度。 { int i = 0; while(1) { i++; if(i%10000000 == 0) { printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid); 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

/*
*  linux/mykernel/myinterrupt.c
*
*  Kernel internal my_timer_handler
*
*  Copyright (C) 2013  Mengning
*
*/
#include <linux/types.h>
#include <linux/string.h> #include <linux/ctype.h> #include <linux/tty.h> #include <linux/vmalloc.h> #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; /* * Called by timer interrupt. * it runs in the name of current running process, * so it use kernel stack of current running process */ void my_timer_handler(void) /* 用于设置时间片的大小,时间片用完时设置调度标志。 当时钟中断发生1000次,并且my_need_sched!=1时,把my_need_sched赋为1。 当进程发现my_need_sched=1时,就会执行my_schedule。 */ { #if 1 if(time_count%1000 == 0 && my_need_sched != 1) { 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 */ { /* switch to next process */ /*如果下一个进程的状态是正在执行的话,就运用if语句中的代码表示的方法来切换进程*/ asm volatile( "pushl %%ebp\n\t" /* save ebp 保存当前进程的ebp*/ "movl %%esp,%0\n\t" /* save esp 保存当前进程的esp*/ "movl %2,%%esp\n\t" /* restore esp 把下一个进程的sp放到esp中*/ "movl $1f,%1\n\t" /* save eip 保存eip*/ "pushl %3\n\t" "ret\n\t" /* restore eip */ "1:\t" /* next process start here */ "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" /* save ebp */ "movl %%esp,%0\n\t" /* save esp */ "movl %2,%%esp\n\t" /* restore esp */ "movl %2,%%ebp\n\t" /* restore ebp */ "movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t" "ret\n\t" /* restore eip */ : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) ); } return; }

王玥 原创作品转载请注明出处  《Linux内核分析》MOOC课



转载于:https://www.cnblogs.com/disturbia/p/5245004.html

Linux内核分析 笔记二 操作系统是如何工作的 ——by王玥相关推荐

  1. 庖丁解牛linux内核 百度云,庖丁解牛Linux内核分析笔记-1

    2019-5-3 主要内容摘自 孟宁<庖丁解牛Linux内核分析> 天下大事必作于细,天下难事必作于易 1.计算机三大法宝 存储程序计算机 函数调用堆栈 中断 2.虚拟一个x86的CPU硬 ...

  2. 庖丁解牛山linux内核的析,# 庖丁解牛Linux内核分析笔记-1

    2019-5-3 主要内容摘自 孟宁<庖丁解牛Linux内核分析> 天下大事必作于细,天下难事必作于易 1.计算机三大法宝 存储程序计算机 函数调用堆栈 中断 2.虚拟一个x86的CPU硬 ...

  3. Linux内核分析 笔记七 可执行程序的装载 ——by王玥

    一.预处理.编译.链接和目标文件的格式 (一)可执行程序是怎么得来的? 1. 2.可执行文件的创建--预处理.编译和链接 shiyanlou:~/ $ cd Code                  ...

  4. Linux内核分析第一周——计算机是如何工作的

    冯诺依曼体系结构 核心思想 1.冯诺依曼是:数字计算机的数制采用二进制:计算机应该按照程序顺序执行. 2.采用二进制作为计算机数值计算的基础,以0.1代表数值.不采用人类常用的十进制计数方法,二进制使 ...

  5. 庖丁解牛Linux内核分析01:操作系统工作原理基础

    目录 1 存储程序计算机工作模型 2 IA-32汇编基础 2.1 寄存器概述 2.1.1 通用寄存器 2.1.2 段寄存器 2.1.3 标志寄存器 2.2 数据格式 2.3 寻址方式 2.3.1 立即 ...

  6. Linux内核分析 笔记六 进程的描述和进程的创建 ——by王玥

    一.知识点总结 (一)进程的描述 1.操作系统内核里有三大功能: 进程管理 内存管理 文件系统 2.进程描述符:task_struct 2.进程描述符--struct task_struct 1. p ...

  7. linux内核视频 网易,网易云课堂linux内核分析(二)

    前言 这是第二周的报告.本周的实验是:完成一个简单的时间片轮转多道程序内核代码,代码见视频中或从mykernel找. 老师已经为我们搭好了实验的环境--linux3.9.4下一个极其迷你的系统.我们不 ...

  8. Linux内核分析 - 网络[二]:网卡驱动接收报文

    纠结了好多天,终于弄懂了B440X的处理. 上篇讲到通过中断,最终网卡调用了b44_rx()来接收报文 对这个函数中的一些参数,可以这样理解: bp->rx_cons – 处理器处理到的缓冲区号 ...

  9. 《Linux内核分析》 第二节 操作系统是如何工作的

    Linux内核分析 第二周 操作系统是如何工作的 张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/UST ...

最新文章

  1. Django—模板渲染
  2. zabbix源码安装 令人窒息的操作
  3. hashmap为什么是2的倍数_HashMap源码解析(jdk1.8)
  4. php本地文件打包代码,PHP实战:几行代码轻松实现PHP文件打包下载zip
  5. android的四大组件及使用场景,Android/四大组件/Activity.md · BoraxZYF/AndroidInterview - Gitee.com...
  6. 逆向libbaiduprotect(二)
  7. BZOJ2563: 阿狸和桃子的游戏 贪心
  8. Hadoop yarn配置参数
  9. System.Timers.Timer(定时器)
  10. 人民币转换美金的c语言代码大全,C语言 人民币转换代码
  11. faster rcnn 计算mAP
  12. 单项选择题标准化考试系统
  13. 解决Excel表格输入身份证号码显示异常的问题
  14. Django笔记 CMS框架Mezzanine 2
  15. A系统单点登录B系统
  16. 春节大礼包!——海多PS游戏下载及PS模拟器EPSXE VGS设置指南
  17. Pytorch实现yolov3(train)训练代码详解(二)
  18. sincerit 算法竞赛宝典--油桶问题
  19. 计算机文化节闭幕式祝福语,快讯 | 第十三届计算机文化节闭幕式暨专家讲座圆满落幕...
  20. C语言 第一节 简单的C语言

热门文章

  1. phpcms v9 邀请用户注册自动获取积分奖励
  2. 2022-2027年中国降糖药行业市场调研及未来发展趋势预测报告
  3. 解决客户之间的矛盾-生米煮成熟饭
  4. 鸟哥的Linux私房菜-基础学习篇(第四版):鸟哥-电子书
  5. Swift面试资料 (一) —— Questions 和 Answers(一)
  6. “含沙射影”?【空心杯微电机】映射冷行业
  7. python代码少的作品_原创 8行python代码展示程序员从入门到大神(或跑路)的全部状态...
  8. centos 6.5 httpd 自建CA 认证 实现 https 服务
  9. 连续系统的卷积积分与离散系统的卷积和
  10. 钉钉第三方登录,多地址授权