linux内核第二周
chapter 1 知识点梳理
(一)计算机是如何工作的?(总结)——三个法宝
①存储程序计算机工作模型,计算机系统最最基础性的逻辑结构;
②函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语言的时候堆栈机制对于计算机来说并不那么重要,但有了高级语言及函数,堆栈成为了计算机的基础功能;
- 1234567
enterpushl %ebpmovl %esp,%ebpleavemovl %ebp,%esppopl %ebp 函数参数传递机制和局部变量存储
③中断,多道程序操作系统的基点,没有中断机制程序只能从头一直运行结束才有可能开始运行其他程序。
(二)函数调用堆栈
堆栈
1.堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间。
2.堆栈存在的目的:函数调用框架;传递参数;保存返回地址;提供局部变量空间;等等。
3.C语言编译器对堆栈的使用有一套的规则。
4.了解堆栈存在的目的和编译器对堆栈使用的规则是理解操 作系统一些关键性代码的基础。
堆栈寄存器和堆栈操作
|
1
2
|
pop:从高地址向低地址push:从低地址向高地址 |
1.堆栈相关的寄存器:esp,堆栈指针(stack pointer):ebp,基址指针(base pointer)
2.堆栈操作:push 栈顶地址减少4个字节(32位) pop 栈顶地址增加4个字节
3.ebp在C语言中用作记录当前函数调用基址
其他关键寄存器
cs : eip:总是指向下一条的指令地址
|
1
2
3
4
5
|
顺序执行:总是指向地址连续的下一条指令跳转/分支:执行这样的指令的时候,cs : eip的值会 根据程序需要被修改call:将当前cs : eip的值压入栈顶,cs : eip指向被 调用函数的入口地址ret:从栈顶弹出原来保存在这里的cs : eip的值,放 入cs : eip中发生中断时 |
(三)借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断
当一个中断信号发生时,CPU把当前的eip,esp,ebp压到内核堆栈中去,并把eip指向中断处理程序的入口。
C代码中嵌入汇编代码
(四)在mykernel基础上构造一个简单的操作系统内核
chapter 2 实验
1.实验步骤1:
每执行my_ start_ kernel函数两次或一次,my_ time_ hander函数执行一次。
2.实验步骤2:mymain.c

3.实验步骤3:myinterrupt.c


4.程序分析
mypcb.h
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/* * 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 未运行, 0 运行中, >0 阻塞停止 */ char stack[KERNEL_STACK_SIZE]; /* 定义堆栈结构*/ struct Thread thread; unsigned long task_entry; /* 定义程序入口,通常是main函数*/ struct PCB *next; }tPCB; void my_schedule(void);//调度器函数 |
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]; //声明一个PCB数组
tPCB * my_current_task = NULL; //声明当前task指针
volatile int my_need_sched = 0; //是否需要调度标志 void my_process(void); void __init my_start_kernel(void)
{
int pid = 0;
int i;
/* 初始化 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; /* 实际上是my_process*/
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
task[pid].next = &task[pid]; // 定义堆栈的栈顶
/*创建更多的子进程*/
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];
}
/* 从0号进程开始启动 */
pid = 0;
my_current_task = &task[pid];
asm volatile(
"movl %1,%%esp\n\t" /* 设置 esp 的值*/
"pushl %1\n\t" /* 将 ebp 压栈(此时esp=ebp),%1相当于task[pid].thread.sp*/
"pushl %0\n\t" /* 将 eip 压栈,%0相当于task[pid].thread.ip*/
"ret\n\t" /* 相当于 eip 出栈 */
"popl %%ebp\n\t" /* 0号进程正是启动 */
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/
);
}
void my_process(void)
{
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)
{
#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
|| my_current_task->next == NULL)
{
return;
}
printk(KERN_NOTICE ">>>my_schedule<<<\n");
/* schedule */
next = my_current_task->next;
prev = my_current_task;
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,%2为 next->thread.sp*/
"movl $1f,%1\n\t" /* 保存当前 eip ,%1为prev->thread.ip*/
"pushl %3\n\t"
"ret\n\t" /* 记录要跳转进程的 eip,%3为 next->thread.ip*/
"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);
/* switch to new process */
asm volatile(
"pushl %%ebp\n\t" /* 保存当前 ebp */
"movl %%esp,%0\n\t" /* 保存当前 esp */
"movl %2,%%esp\n\t" /* 重新记录要跳转进程的 esp ,%2为 next->thread.sp*/
"movl %2,%%ebp\n\t" /* 重新记录要跳转进程的 ebp,%2为 next->thread.sp */
"movl $1f,%1\n\t" /* 保存当前 eip ,%1为prev->thread.ip,%1f就是指标号1:的代码在内存中存储的地址*/
"pushl %3\n\t"
"ret\n\t" /* 重新记录要跳转进程的 eip,%3为 next->thread.ip */
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
}
return;
}


chapter 3 总结
操作系统工作的基础:
操作系统的内核有一个起始位置,从这个起始位置开始执行。开始工作时,CPU分配给第一个进程,开始执行第一个进程,然后通过一定的调度算法,比如时间片轮转,在一个时间片后,发生中断
,第一个进程被阻塞,在完成保存现场后将CPU分配给下一个进程,执行下一个进程。这样,操作系统就完成了基本的进程调度的功能。存储程序计算机、堆栈机制、中断机制。操作系统是管理电脑
硬件与软件资源的程序,同时也是计算机系统的内核与基石。操作系统是管理计算机系统的全部硬件资源包括软件资源及数据资源;控制程序运行;改善人机界面;为其它应用软件提供支持等,使计算
机系统所有资源最大限度地发挥作用,为用户提供方便的、有效的、友善的服务界面。操作系统是一个庞大的管理控制程序,大致包括5个方面的管理功能:进程与处理机管理、作业管理、存储管理
、设备管理、文件管理。Linux系统有一个进程控制表(process table),一个进程就是其中的一项。进程控制表中的每一项都是一个task_struct结构,在task_struct结构中存储各种低级和高级
的信息,包括从一些硬件设备的寄存器拷贝到进程的工作目录的链接点。进程控制表既是一个数组,又是一个双向链表,同时又是一个树,其物理实现是一个包括多个指针的静态数组。系统启动后,
内核通常作为某一个进程的代表。一个指向task_struct的全局指针变量current用来记录正在运行。
:::::郝爽 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000
linux内核第二周的更多相关文章
- linux 内核 第二周 操作系统是如何工作的
姬梦馨 原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一:计算机的三个法宝 存储程序计算机工 ...
- Linux内核第二节
作者:武西垚 深入理解函数调用堆栈 堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间 堆栈的作用 函数调用框架 传递参数 保存返回地址 提供局部变量空间 堆栈相关的寄存器 esp,堆栈指针,指 ...
- linux安全第二周学习总结
一.实验过程 cd LinuxKernel/linux-3.9.4 qemu -kernel arch/x86/boot/bzImage 然后cd mykernel 您可以看到qemu窗口输出的内容的 ...
- linux作业--第二周
1.显示/etc目录下,以非字母开头,后面跟了一个字母以及其它任意长度任意字符的文件或目录 ls /etc/ | grep ^[^[:alpha:]][[:alpha:]].* 2.复制/etc目录下 ...
- linux内核书籍
1, 关于操作系统理论的最初级的知识.不需要通读并理解<操作系统概念><现代操作系统>等巨著,但总要知道分时(time-shared)和实时(real-time)的区别是什么, ...
- linux内核体系结构
linux内核第一记 1.linux体系结构 从上图可知,Linux分为:用户空间和内核空间.内核空间和用户空间是程序执行的两种不同的状态,通过系统调用和硬件中断能够完成从用户空间到内核空间的 ...
- Linux内核设计第二周——操作系统工作原理
Linux内核设计第二周 ——操作系统工作原理 作者:宋宸宁(20135315) 一.实验过程 图1 执行效果 从图中可以看出,每执行my_ start_ kernel函数两次或一次,my_ time ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 20169210《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...
随机推荐
- JAVAWEB基础模块开发顺序与数据访问对象实现类步骤
一.模块的开发的顺序 1. 定义数据表 2. 新建模型类 3. 新建"add.jsp" 4. 实现AddServlet中的doGet()方法 5. 定义Dao.Service接口 ...
- IT资料常用网址汇总
菜鸟联盟: http://www.runoob.com/ w3c school :https://www.w3cschool.cn/ http://www.w3school.com.cn/w3c/in ...
- 在虚拟机中的搭建Web服务器(CentOS)
1.制作本地yum源 相关可查看:http://www.cnblogs.com/xiaomingzaixian/p/8424290.html 2.安装JDK 上传上传jdk-7u45-linux-x6 ...
- [iOS微博项目 - 4.5] - 每条微博的底部工具条
github: https://github.com/hellovoidworld/HVWWeibo A.每条微博的底部工具条 1.需求 每条微博底部都有一个工具条 显示3个按钮:评论.转发.赞 按钮 ...
- redis之数据操作详解
redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...
- Linux Anaconda安装步骤
首选下载wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh 可以去官网查看适合自己的文件https://www ...
- wordpress 自己制作子主题 child theme
使用 WordPress 的子主题(Child Themes)功能快速制作自己的主题 在了解子主题功能之前,先来看一下你在使用 WordPress 的时候是否是这样:不会自己制作主题,只好从网上下载一 ...
- volatile变量,java内存模型
volatile变量提供了最轻量级的同步机制,当一个变量加上volatile修饰时,会具有一下两个特性 https://blog.csdn.net/u011277123/article/details ...
- .........请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。
今天研究membership的时候出现的问题.在此记录一下. 解决办法就是,将"C:\Program Files (x86)\Microsoft Web Tools\Packages\Asp ...
- python学习笔记(二十七)多线程与多进程
线程是程序里面的最小执行单元. 进程是资源的集合. 线程是包含在一个进程里面,一个进程可以有多个线程,一个进程里面默认有一个主线程.由主线程去启动子线程. 1.多线程 import threading ...
