09保护模式下的进程调度Word文档下载推荐.docx
《09保护模式下的进程调度Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《09保护模式下的进程调度Word文档下载推荐.docx(39页珍藏版)》请在冰豆网上搜索。
●初始化IDTprotect.c:
init_prot()*
●在GDT中添加TSS和3个LDT描述符*
●初始化TSS**************************
●初始化进程表************************
●设置时钟中断处理程序*
●打开时钟中断main.c:
kerel_main()*
●调用restart***************************
●进程切换-----------------------------------------------------
1.2程序目录
下面是我们程序目录ps中的子目录结构及文件的功用。
tree
.
├──a.img(FAT12软盘映像:
将复制进文件LOADER.BIN和KERNEL.BIN)
├──boot(引导&
装入)
│
├──boot.asm(引导扇区:
FAT12、装入LOADER.BIN)
├──include(包含汇编程序)
│
├──fat12hdr.inc(FAT12的常量定义)
├──load.inc(装载地址的常量定义)
└──pm.inc(保护模式的常量与宏定义)
└──loader.asm(装载程序:
获取并显示内存信息、定义并初始化GDT、
├──include(包含头文件)进入保护模式、启动分页机制、加载kernel)
├──const.h(定义类型和常量)
├──global.h(定义全局数据结构[数组])
├──proc.h(定义进程表和任务结构)
├──protect.h(定义保护模式下的数据结构类型和符号常量)
├──proto.h(定义函数的原型)
├──sconst.inc(定义汇编程序用的PCB、时钟控制器常量和选择符常量)
├──string.h(定义memcpy和memset的函数原型)
└──type.h(定义无符号整数和函数指针类型)
├──kernel(内核程序)
├──clock.c(定义时钟中断处理程序clock_handler)
├──global.c(定义全局数据结构[数组])
├──i8259.c(初始化时钟控制器)
├──kernel.asm(切换GDT、装入IDT和TTS、调用main.c中的kerel_main()、
定义异常和硬件中断处理、定义save和restart函数)
├──main.c(初始化进程表、定义用户进程函数)
├──protect.c(定义异常与硬件中断处理、初始化TSS和LDT描述符)
└──start.c(复制GDT、初始化IDT)
├──lib(库函数)
├──kliba.asm(定义显示串、端口I/O和开闭硬件中断的汇编函数)
├──klib.c(定义整数转字符串、显示整数和延时函数)
└──string.asm(定义内存复制、内存设置和串复制函数)
└──Makefile(定义用于自动编译和软盘挂载/文件复制的Make文件)
1.3逻辑框图
与实模式下进程调度的类似。
1.4运行结果
2程序模块
boot.asm与我们的boot5.asm相同,loader.asm及其3个包含文件fat12hdr.inc、load.inc和pm.inc与上次实验中的相同,没有必要重复介绍。
下面只是关于内核程序诸模块的功能介绍与代码分析。
2.1应用程序函数
为了简单,我们在内核程序组中增加了C程序main.c,在其中初始化进程表,并定义3个函数TestA、TestB、TestC来充当3个用户进程。
2.1.1进程函数TestX
这些进程函数很简单,只是显示字符串“A”/“B”/“C”+计数+句点的死循环。
下面它们的C语言源代码(main.c):
/*===========================================================*
TestA
*===========================================================*/
voidTestA()
{
inti=0;
while
(1){
disp_str("
A"
);
disp_int(i++);
."
delay
(1);
}
}
TestB
voidTestB()
inti=0x1000;
B"
TestC
voidTestC()
inti=0x2000;
C"
2.1.2串显示函数disp_str
进程函数中的字符串显示函数disp_str被定义在汇编库程序kliba.asm(也与上次实验的相同)中:
;
=============================================================
voiddisp_str(char*info);
disp_str:
pushebp
movebp,esp
movesi,[ebp+8];
pszInfo
movedi,[disp_pos]
movah,0Fh
.1:
lodsb;
ds:
esi->
al
testal,al
jz.2
cmpal,0Ah;
是回车吗?
jnz.3
pusheax
moveax,edi
movbl,160
divbl
andeax,0FFh
inceax
mulbl
movedi,eax
popeax
jmp.1
.3:
mov[gs:
edi],ax
addedi,2
.2:
mov[disp_pos],edi
popebp
ret
该函数通过改写显存内容来显示字符(绿色代码)。
在此函数中字符串被显示在由全局变量disp_pos所指定的位置,显示完后再更新该变量的值(红色代码)。
如果显示的字符是回车符,则让EAX=EDI(=disp_pos),EAX/160=AL,EDI=(AL++)*160为下一行的首地址(蓝色代码)。
因每行80列,每个字符位占两个字节(AL=字符、AH=颜色),所以一行为160B。
2.1.3延时函数delay
延时函数delay则被定义在C库程序klib.c中,它是一个三层循环,最外层的循环是函数的输入参数,在我们的程序中取为1:
delay
PUBLICvoiddelay(inttimes)
inti,j,k;
for(k=0;
k<
times;
k++){
for(i=0;
i<
10;
i++){
for(j=0;
j<
10000;
j++){}
}
2.2入口函数
内核的入口在kernel.asm的_start函数(与上次实验的5.1中的代码相似,红色代码为不同的部分)中:
_start:
;
把esp从LOADER挪到KERNEL
movesp,StackTop;
堆栈在bss段中
movdword[disp_pos],0
sgdt[gdt_ptr];
cstart()中将会用到gdt_ptr
callcstart;
在此函数中改变了gdt_ptr,让它指向新的GDT
lgdt[gdt_ptr];
使用新的GDT
lidt[idt_ptr]
jmpSELECTOR_KERNEL_CS:
csinit
csinit:
“这个跳转指令强制使用刚刚初始化的结构”
xoreax,eax
movax,SELECTOR_TSS
ltrax
jmpkernel_main
这段代码所完成的工作有:
●更新堆栈指针ESP=StackTop(跳转到kernel时已经切换了SS)
●初始化disp_pos=0
●切换GDT:
保存老GDTR、调用cstar(复制GDT、初始化IDT)、装入新GDT
●装入IDT和TSS
●跳转到main.c中的kerel_main()函数来初始化进程表、设置时钟中断处理程序、打开时钟中断、调用restart函数
在汇编程序kernel.asm中还
●