📄 05.htm
字号:
onmouseover="MM_swapImage('Image173','','../images/developers/button3_bottom.gif',1)"
onmouseout=MM_swapImgRestore()
href="http://developer.ccidnet.com/pub/disp/Column?columnID=293"
target=_blank><IMG height=18 src="05.files/button3_top.gif" width=66
border=0 name=Image173></A></DIV></TD>
<TD bgColor=#cccc98 height=22><IMG height=13 src="05.files/line.gif"
width=1></TD>
<TD bgColor=#cccc98 height=22>
<DIV align=center><A
onmouseover="MM_swapImage('Image174','','../images/developers/button4_bottom.gif',1)"
onmouseout=MM_swapImgRestore()
href="http://developer.ccidnet.com/pub/disp/Column?columnID=296"
target=_blank><IMG height=18 src="05.files/button4_top.gif" width=66
border=0 name=Image174></A></DIV></TD>
<TD bgColor=#cccc98 height=22><IMG height=13 src="05.files/line.gif"
width=1></TD>
<TD bgColor=#cccc98 height=22>
<DIV align=center><IMG height=18 src="05.files/button5_bottom.gif"
width=50 border=0 name=Image165></DIV></TD>
<TD bgColor=#cccc98 height=22><IMG height=13 src="05.files/line.gif"
width=1></TD>
<TD bgColor=#cccc98 height=22>
<DIV align=center><A
onmouseover="MM_swapImage('Image176','','../images/developers/button6_bottom.gif',1)"
onmouseout=MM_swapImgRestore()
href="http://developer.ccidnet.com/pub/disp/Column?columnID=315"
target=_blank><IMG height=18 src="05.files/button6_top.gif" width=50
border=0 name=Image176></A></DIV></TD>
<TD bgColor=#cccc98 height=22><IMG height=13 src="05.files/line.gif"
width=1></TD>
<TD bgColor=#cccc98 height=22>
<DIV align=center><A
onmouseover="MM_swapImage('Image177','','../images/developers/button7_bottom.gif',1)"
onmouseout=MM_swapImgRestore()
href="http://bbs.ccidnet.com/forumdisplay.php?forumid=13"
target=_blank><IMG height=18 src="05.files/button7_top.gif" width=80
border=0 name=Image177></A></DIV></TD>
<TD width=17 bgColor=#ffffff height=22><IMG height=24
src="05.files/right_yuan.gif" width=18></TD></TR></TBODY></TABLE><!-- 包含菜单结束-->
<TABLE cellSpacing=0 cellPadding=0 width=580 align=center border=0>
<TBODY>
<TR>
<TD class=content vAlign=top colSpan=2 height=20><IMG height=5
src="" width=5><BR><!-- 包含导航开始--><!-- 模版文件头 结束 -->
<TABLE class=content01 cellSpacing=1 width=414 border=0>
<TBODY>
<TR>
<TD width="100%"><IMG height=10 src="05.files/triangle.gif"
width=11> 当前页面位置:<A class=link
href="http://www.ccidnet.com/">主页</A> :<A class=link
href="http://developer.ccidnet.com/pub/disp/Column?columnID=287&pageNO=1">开发者</A>:<A
class=link
href="http://developer.ccidnet.com/pub/disp/Column?columnID=301&pageNO=1">Linux</A>:<A
class=link
href="http://developer.ccidnet.com/pub/disp/Column?columnID=303&pageNO=1"><B>技术开发</B></A><B>:文章</B>
</TD></TR></TBODY></TABLE><!-- 包含导航结束--></TD>
<TR>
<TD colSpan=2 height=10></TD></TR>
<TR bgColor=#7e99a4>
<TD colSpan=2 height=2></TD></TR>
<TR>
<TD class=content vAlign=top colSpan=2 height=15>
<DIV align=right><!-- 包含发送email开始-->
<FORM name=sendmail
action=http://club.ccidnet.com/send_to_friend.php3 method=post
target=_blank><INPUT type=hidden value=编写实模式多任务操作系统模型之二 name=title>
<INPUT type=hidden value="高克强 王兴泰" name=author> <INPUT type=hidden
value="2002.12.31 11:20:57" name=publish_time> <INPUT type=hidden
value=Article?columnID=303&articleID=35453&pageNO=1
name=link> </FORM><IMG height=5 src="" width=5><BR><A
class=content01 href="javascript:self.print()"><IMG title=打印
height=18 src="05.files/printer.gif" width=24 border=0>打印</A> <A
class=content01 href="javascript:document.sendmail.submit()"><IMG
title=发给朋友 height=18 src="05.files/comment.gif" width=24
border=0>发给朋友</A> <A class=content01
href="http://club.ccidnet.com/remark.php3?channel=303&title=编写实模式多任务操作系统模型之二"><IMG
title=发表评论 height=18 src="05.files/send.gif" width=24
border=0>发表评论</A> <!-- 包含发送email结束--></DIV></TD></TR><!-- 包含文章开始--><!-- 文章显示 -->
<TR>
<TD class=content vAlign=top width=19></TD>
<TD class=content vAlign=top width=561><IMG height=5 src=""
width=5><BR><SPAN
class=p16><B>编写实模式多任务操作系统模型之二(2)</B></SPAN><BR>作者:高克强 王兴泰
本文选自:开放系统世界——赛迪网 2002年12月31日 </TD></TR>
<TR>
<TD class=content vAlign=top width=19></TD>
<TD class=content vAlign=top width=561 height=144><BR><SPAN
class=p11b><IFRAME align=right marginWidth=0 marginHeight=0
src="C:\Documents and Settings\Administrator\My Documents\freeos\temp\os\05.files\ad(3).htm"
frameBorder=0 noResize width=360 scrolling=no
height=300></IFRAME>5.切换到下一将被调度运行task2的进程堆栈空间。由于在进程堆栈保存有进程的断点信息,所以找到进程堆栈的顶位置便可转入到该进程运行。scheduler对于各进程的调度采用轮转式的方式,即按照task1
--> task2 --> task3的顺序,而后再从task1
开始依次循环,使各个进程得以运行。所以将current_task的值增1,再判断current_task是否超过最大进程数MAXTASKS,若超过,则使其复位,从0开始重新计数即可。取得合适的current_task值后,按上面步骤的公式便可找到将被调度进程的堆栈指针的存放地址,从中取出值送到SP寄存器即可。如下段程序代码所示:
<BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550
align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6><PRE><CCID_CODE>inc ax ; 取得下一将被调度进行的进程号
cmp ax, MAXTASKS ; 该进程号是否超过最大进程数
jb move_on ; 若没超过,跳到 move_on 继续
xor ax, ax ; 超过最大进程数,清0,从第一个进程开始调度
move_on:
mov [current_task], ax
;将更改后进程号送入current_task单元保存,按公式进程堆栈指针的存放地址=SPtable+2*进程号
取得进程堆栈指针
mov bx, ax
shl bx, 1
lea si, [SPtable]
mov SP, [ds:si + bx] ; 将进程堆栈指针送到SP,切换到进程堆栈空间</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR>6.
恢复断点信息,使下一被调度进程从断点处运行。 <BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550
align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6><PRE><CCID_CODE>pop ds
pop es
popa ;恢复所有被保存的CPU内寄存器值
iret ;激活被调度进程</CCID_CODE></PRE></TD></TR></TBODY></TABLE></CCID_NOBR><BR><BR><B>其它辅助程序</B>
<BR><BR>系统中存在3个被调度的程序,分别为task1、task2、task3。由于这是一个实验程序,所以它们的功能较为单一,主要是将自身的一个16位计数器进行循环计数,而后通过直接写屏方式在显示器上显示出来。由于现行机器的运行速度较快,为使用户能看清计数器的变化过程,在各个进程的执行过程中加入了人为的延时控制。每一个进程都是一个无限的循环过程,只要调度程序在运行,各个进程就会无限运行。
<BR><BR>此外系统中还有几个辅助程序: <BR><BR>◆ 16进制数显示子程序printhex
<BR><BR>这个子程序主要是为系统内的3个演示进程服务,它可以将从堆栈传递过来的一个16位的数以16进制形式显示到屏幕的指定位置,通过直接写屏方式在显示器上显示出来。在VGA的
80X25
彩色文本显示模式下,一个字符在显示缓冲区上占2个字节的空间,其中所显示字符的ASCⅡ码存于低地址单元中,字符的显示属性(前景、背景、高亮和闪烁等)存于高地址单元中,如果将字符及其显示属性存储位置弄错,将会产生花屏的现象。Printhex根据显示位置参数计算出所需显示的准确位置,避免产生花屏的现象。调用者只需提供合法的显示位置即可,行号应在1~25之间,列号在1~80之间。
<BR><BR>◆ 键盘中断子程序keybd
<BR><BR>它是一个基本的内核级键盘中断处理程序,显示键盘的ASCⅡ码到屏幕上。它不受调度进程的控制,只要有键盘中断发生,该中断服务程序就会运行。在该程序被触发运行时,从60H端口读入键盘的扫描码。扫描码最高位的状态标志着其是键入码还是释放码,如为释放码则不进行处理,直接返回;若为按键的压入码,则以键入码作为索引在键盘扫描码/ASCⅡ码对照表查得对应的ASCⅡ码,通过int
10h功能调用将其输出到显示器上。在键盘中断返回前,要向键盘内的单片机发复位信号,
先将61h端口的最高位置1,而后再置0,这样键盘才不会死锁。 <BR><BR>kernel.asm完整代码及注释如下:
<BR><BR><CCID_NOBR>
<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=550
align=center borderColorLight=black border=1>
<TBODY>
<TR>
<TD class=code bgColor=#e6e6e6><PRE><CCID_CODE>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 内核程序kernel.asm
; 在系统时钟中断的驱动下,依次使系统内的3个进程轮流占用CPU完成各
; 自的工作:在屏幕上指定位置循环显示自己的计数器。具有内核级键盘中
; 断,显示出键盘ASCII码
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 16]
[ORG 0x00]
STACKSIZE equ 0x400 ; 各进程的堆栈空间大小为1k个字节
MAXTASKS equ 3 ; 最大进程数
VIDEORAM equ 0xb800 ; 显示缓存段地址
KERNELSEG equ 0x8000 ; kernel 程序段地址
;------------------------------------------------------------------
start:
mov ax,KERNELSEG
mov ds, ax ; 数据段,堆栈段寄存器的
mov ss, ax ; 值均设为 KERNELSEG
mov sp, 0xFFFF ; kernel 堆栈指针=0xFFFF
mov dx,0x3f2
mov al,0x0c
out dx,al ;关闭软驱马达
mov ax, 0x0003
int 0x10 ; 清屏
mov dx, 0x0600 ; 进程的堆栈基地址
add dx, STACKSIZE ; 进程1的堆栈指针= 0xA00
mov ax, task1 ; 进程1入口地址
call taskinit ; 初始化进程1
add dx, STACKSIZE ; 进程2的堆栈指针= 0xD00
mov ax, task2 ; 进程2入口地址
call taskinit ; 初始化进程2
add dx, STACKSIZE ; 进程3的堆栈指针= 0x1000
mov ax, task3 ; 进程3入口地址
call taskinit ; 初始化进程3
; 重新设置系统定时器的中断向量
cli ;关中断,以免在设置中断向量发生意外
mov ax, KERNELSEG
push ds ;保存ds值
mov bx,0
mov ds,bx ;ds=0
mov word [ds:0x08*4], scheduler ; 定时器中断向量偏移送到0:20~0:21
mov word [ds:0x08*4+2], ax ; 定时器中断向量段地址送到0:22~0:23
; 重新设置键盘的中断向量
mov word [ds:0x09*4], keybd ; 键盘的中断向量偏移送到0:24~0:25
mov word [ds:0x09*4+2], ax ; 键盘的中断向量段地址 0:26~0:27
pop ds ; 恢复ds值
sti ; 开中断,允许中断进入
jmp $ ; kernel在此等待时钟中断的到来
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 被调度进程task1
; 功能:对于自身的计数器进行计数,而后在屏幕的3行1显示输出
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
task1:
.l1 dec word [task1ctra] ; 产生短时间延迟,以免计数显示过快
jnz .l1
inc word [task1ctr] ; 计数器增1
push word 3 ; 输出行号
push word 0 ; 输出列号
push word [task1ctr] ; 将参数通过堆栈进行传递
call printhex ; 调用16进制显示子程序
jmp task1 ; 循环显示
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 被调度进程task2
; 功能:对于自身的计数器进行计数,而后在屏幕的6行1显示输出
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
task2:
.l1 dec word [task2ctra]
jnz .l1
inc word [task2ctr]
push word 6
push word 0
push word [task2ctr]
call printhex
jmp task2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 被调度进程task3
; 功能:对于自身的计数器进行计数,而后在屏幕的9行1显示输出
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
task3:
.l1 dec word [task3ctra]
jnz .l1
inc word [task3ctr]
push word 9
push word 0
push word [task3ctr]
call printhex
jmp task3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;任务初始化子程序taskinit
;功能: 在被初始化进程的堆栈空间中压入Flag寄存器,进程的入口
; 地址,及要被保护的CPU寄存器值,同时将进程的栈顶地址
; 写入sptable数组中。
;参数: bx= 进程的堆栈指针
; ax= 进程的入口地址偏移
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
taskinit:
pusha
push es
push ds ; 将现场保护到在kernel的的堆栈空间中。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -