操作系统是如何工作的
知识点:
三个法宝:
存储程序计算机、函数调用堆栈、中断机制。
堆栈:
堆栈机制是高级语言的起点。
堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间。(函数调用框架、传递参数、保存返回地址、提供局部变量空间等等)
esp总指向栈顶,ebp总指向当前函数基址,eip总指向下一条指令地址。
堆栈操作在上一节已做说明,不再赘述。
内嵌汇编语法:
asm("statement" : output_regs: input_regs: clobbered_regs);
加volatile表示不要优化代码。
mykernel实验:
使用实验楼的虚拟机打开shell
cd LinuxKernel/linux-3.9.4
qemu -kernel arch/x86/boot/bzImage
然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c
代码非常简单就是正常运行时打印上面,中断时打印下面。
下面是一个简单的时间片轮转多道程序内核代码。
mypcb.h
#define MAX_TASK_NUM 4
#define KERNEL_STACK_SIZE 1024*8
/* CPU-specific state of this task */
struct Thread {
unsigned long ip;
unsigned long sp;
};
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);
定义一个进程控制块pcb结构体
task_entry:进程入口函数
thread:保存eip和esp
state:进程状态,用于判断是否调度
mymain.c
代码过长不再列出,主要功能是让程序从0号进程开始运行。
下面这段代码是核心。
asm volatile(
//%0表示参数thread.ip,%1表示参数thread.sp。
"movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp 把参数thread.sp放到esp中*/
"pushl %1\n\t" /* push ebp 由于当前栈是空的,esp与ebp指向相同,所以等价于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*/
);
myinterrupt.c
主要功能是用于时钟中断处理和进程调度算法。
同样注意这样一段代码。
asm volatile(
"pushl %%ebp\n\t" /* save ebp 保存当前进程的ebp*/
"movl %%esp,%0\n\t" /* save esp 把当前进程的esp赋给%0(指的是thread.sp),即保存当前进程的esp*/
"movl %2,%%esp\n\t" /* restore esp 把%2(指下一个进程的sp)放入esp中*/
"movl $1f,%1\n\t" /* save eip $1f是接下来的标号“1:”的位置,把eip保存下来*/
"pushl %3\n\t" /*把下一个进程eip压栈*/
"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)
);
操作系统是如何工作的?
操作系统通过存储程序计算机机制依次执行程序的指令,堆栈为程序运行时录调用路径和参数提供空间,中断用于异常处理和进程调度。