wu5795175的专栏

每有会意,便欣然忘食

linux-0.00源代码

linux-0.00很简单,两个进程task0,task1,task0打印A,task1打印B,在时钟中断中调度进程运行。

据说后来linus丢失了这个最初的版本,这里是赵炯博士写的linux-0.00版本。

我把源代码上传到了csdn的资源里面,在这里下载,可以用bochs模拟,赶紧试试吧微笑

简单说一下,就两个文件,boot.s和head.s。

head.s被编译成system模块

boot.s编译出的MBR用于将编译出的system模块从软盘中读到内存0x10000处,然后跳到0x10000执行。


head.s编译出的system模块设置好task0的tss0和ldt0,以及task1的tss1和ldt1后,初始化idt和gdt,最后在idt中填入两个中断门描述符:时钟中断timer_interrupt和系统调用中断system_interrupt。

然后构造出task0的人工堆栈环境,使用iret指令跳到task0出执行。


多任务实现的关键代码在时钟中断里,如下

/* Timer interrupt handler */  
.align 2
timer_interrupt:
   push %ds 
   pushl %edx
   pushl %ecx
   pushl %ebx
   pushl %eax
   movl $0x10, %eax     #数据段描述符
   mov %ax, %ds 
   movb $0x20, %al      #向8253发送EOI 
   outb %al, $0x20
   movl $1, %eax
   cmpl %eax, current   #current == x 表示当前运行的是taskx (task0/task1)
   je 1f
   movl %eax, current   #从task0切到task1
   ljmp $TSS1_SEL, $0   #执行这句完之后,就会跳到task1代码处执行,task0的tss0的eip处将被填入下一句代码"jmp 2f"的地址,等到切换到task0的时候,从jmp 2f处开始执行
   jmp 2f
1: movl $0, current     #从task1切到task0
   ljmp $TSS0_SEL, $0   #同上,task1的tss1中的eip将会存入"popl %eax"的地址
2: popl %eax
   popl %ebx
   popl %ecx
   popl %edx
   pop %ds 
   iret

注意跳转的这两句ljmp。让我们来模拟一下:

0. 首先执行的是task0。

1. task0运行过程中发生时钟中断,根据逻辑

ljmp $TSS1_SEL, $0跳入到task1的代码中去,此时会把下一条语句即jmp 2f的地址存入到task0的tss中的eip条目中

2. 从task1的tss1中恢复各个寄存器,使task1运行。

3. task1运行过程中发生时钟中断,根据逻辑

ljmp $TSS0_SEL, $0跳到task0的代码中去,此时会把下一条语句即popl %eax存入到task1的tss中的eip条目中

4. cpu根据task0的tss中的eip条目恢复task0,即task0从jmp 2f往下执行,最后执行iret返回到task0的代码中。

5. task0运行过程中再次发生时钟中断,这时候恢复task1的寄存器上下文,从popl %eax出继续往下执行。

6  ....


这样就形成了task0和task1的多任务运行,对于task0来说,它完全感觉不到task1的存在,每次它的寄存器上下文都能被完整的恢复,对于task1来说也一样。 

时钟中断这个过程是可以重入的,可以把这个过程理解成task0和task1共用(代码共用)的一个私有(执行流私有)过程。

阅读更多
个人分类: linux-0.00
上一篇linus大神的二级指针
下一篇GeekOS 中的进程同步方法
想对作者说点什么? 我来说一句

linux0.01版核心_最原始版源代码

2011年04月05日 58KB 下载

Linux 0.1内核源码与注释 pdf

2009年05月04日 2.25MB 下载

没有更多推荐了,返回首页

关闭
关闭