系统的简单注解 - 7 04_process.asm文件
2017-04-21 11:35
369 查看
该文件包括了系统进程的创建、用户进程的安装、进程控制块链表的控制(运行链表、休眠链表)、进程窗口的绘制、硬盘扇区的读取。
Set_TSS_sel:安装TSS段;
Set_LDT_sel:安装LDT段;
Load_core_task:创建系统进程(权限0);
Load_usr_task:创建用户进程(权限3);
mount_task_running_que:将进程结构安装到运行队列中;
mount_task_run_to_pend_que:将进程结构从运行队列放入暂停队列;
mount_task_pend_to_run_que:将进程结构从暂停队列放入运行队列;
switch_task2:轮转切换当前执行的进程;
wakeup_task:检查进程休眠时间是否到时,并唤醒;
draw_task_window:绘制用户进程窗口;
read_hard_disk_0:从硬盘读取一个逻辑扇区;
代码中的SYS_PROC、USR1_PROC、USR2_PROC分别保存了系统进程、用户进程1、用户进程2的控制块。
;===============================================================================
;=== 本程序包括了进程管理的主要功能: ===
;=== 1.进程结构初始化 ===
;=== 2.进程的安装、启动、唤醒、睡眠 ===
;===============================================================================
;-------------------------------------------------------------------------------
Set_TSS_sel: ;安装TSS段
;输入参数: eax-—TSS段基地址
;输出参数: cx—-gdt中的选择子
push edx ;保存edx
xor ecx, ecx ;ecx清零
sgdt [pgdt] ;获取gdt表长度和基址
mov cx, word [pgdt] ;段界限
mov edx, dword [pgdt+2] ;段基址
inc cx ;gdt表长度
add edx, ecx ;安装地址
mov word [edx], 103 ;TSS段长度的低16位
mov word [edx+2], ax ;TSS段基址的低16位
shr eax, 16 ;TSS段基址右移16位
mov byte [edx+4], al ;TSS段基址的中8位
mov byte [edx+7], ah ;TSS段基址的高8位
mov byte [edx+5], 1_00_0_1001B ;P-1,TYPE-9(可用386TSS段)
mov byte [edx+6], 0_1_0_0_0000B ;G-0,X-1,limit-0
add word [pgdt], 8 ;gdt表长度增加8字节
lgdt [pgdt] ;重新安装gdt表到系统
pop edx ;弹出edx
ret
;-------------------------------------------------------------------------------
Set_LDT_sel: ;安装LDT段
;输入参数: eax-—LDT段基地址
;输出参数: cx—-gdt中的选择子
push edx ;保存edx
xor ecx, ecx ;ecx清零
sgdt [pgdt] ;获取gdt表长度和基址
mov cx, word [pgdt] ;段界限
mov edx, dword [pgdt+2] ;段基址
inc cx ;gdt表长度
add edx, ecx ;安装地址
mov word [edx], 15 ;LDT段长度的低16位
mov word [edx+2], ax ;LDT段基址的低16位
shr eax, 16 ;LDT段基址右移16位
mov byte [edx+4], al ;LDT段基址的中8位
mov byte [edx+7], ah ;LDT段基址的高8位
mov byte [edx+5], 1_11_0_0010B ;P-1,DPL=3,TYPE-2(LDT段)
mov byte [edx+6], 0_1_0_0_0000B ;G-0,X-1,limit-0
add word [pgdt], 8 ;gdt表长度增加8字节
lgdt [pgdt] ;重新安装gdt表到系统
pop edx ;弹出edx
ret
;-------------------------------------------------------------------------------
Load_core_task: ;创建系统进程(权限0)
pushad
;内核任务的TSS段填写,清空缓冲区,使段内所有保留位置0
mov eax, SYS_PROC + proc_ctrl.tss
mov ecx, 104
_init_tss:
mov byte [eax], 0x0
inc eax
loop _init_tss
mov eax, SYS_PROC + proc_ctrl.tss
mov ecx, cr3
mov dword [eax + 0x1c], ecx ;此处的CR3的写入必须要有,因为Set_TSS_sel不会主动加入页目录!!!
;在gdt中写入tss段描述符
call Set_TSS_sel ;安装TSS,段首地址在eax中
mov [SYS_PROC + proc_ctrl.task_sel], cx
ltr cx ;将内核任务写入系统
mov eax, SYS_PROC
mov [SYS_PROC + proc_ctrl.pre_task], eax ;系统进程的前一进程指向自己
mov [SYS_PROC + proc_ctrl.next_task], eax ;系统进程的后一进程也指向自己
;记录当前工作进程
mov eax, SYS_PROC
mov [_task_now], eax ;当前工作进程为系统进程
add eax, proc_ctrl.next_task
mov dword [eax], SYS_PROC ;系统进程控制结构的下一个进程地址 指向自己
mov eax, SYS_PROC
add eax, proc_ctrl.state
mov word [eax], task_running ;工作进程状态为 正在运行
popad
ret
;-------------------------------------------------------------------------------
Load_usr_task: ;创建用户进程(权限3)
;输入参数: eax--用户进程的起始扇区号
;输入参数: ebx--用户进程扇区个数
;输入参数: ecx--进程PROC_CTRL结构的偏移地址
;输出参数: cx—-用户进程TSS段在gdt中的选择子
push eax ;[ebp + 24] 起始扇区号
push ebx ;[ebp + 20] 扇区个数
push ecx ;[ebp + 16] 进程控制结构proc_ctrl的偏移
;用户内存区分配用户“页目录”、“页表1”、“app页”、“用户堆栈esp3”三页
call Alloc_usr_page
push eax ;[ebp + 12] 页目录页
call Alloc_usr_page
push eax ;[ebp + 8] 页表1
call Alloc_usr_page
push eax ;[ebp + 4] app页
call Alloc_usr_page
push eax ;[ebp] 用户堆栈
mov ebp, esp
;将用户页目录、页表1、app页映射到系统进程的前三页
mov eax, [ebp + 12]
or eax, 0x7
mov dword [0xffc00000], eax
mov eax, [ebp + 8]
or eax, 0x7
mov dword [0xffc00004], eax
mov eax, [ebp + 4]
or eax, 0x7
mov dword [0xffc00008], eax
;拷贝系统页目录到用户页目录
mov ecx, 1024
xor edx, edx
_dir_cpy:
mov eax, dword [0xfffff000 + edx]
mov dword [edx], eax
add edx, 4
loop _dir_cpy
;用户页目录最后一项指向自己
mov eax, [ebp + 12]
or eax, 0x7
mov dword [4092], eax
;用户页目录第一项指向页表1
mov eax, [ebp + 8]
or eax, 0x7
mov dword [0], eax
;用户页表1第一项指向用户app页(对应线性地址:0x0-0x1000)
mov eax, [ebp + 4]
or eax, 0x7
mov dword [0x1000], eax
;用户页表1第二项指向权限3堆栈(对应线性地址:0x1000-0x2000)
mov eax, [ebp]
or eax, 0x7
mov dword [0x1004], eax
;将用户进程数据从逻辑扇区拷贝到到用户app页中
mov eax, [ebp + 24]
mov ebx, 0x2000
mov ecx, [ebp + 20]
_cpy_disk:
call read_hard_disk_0
inc eax
loop _cpy_disk
;将调用门信息写入用户进程
mov ax, word [far_caller_1 + 4]
mov [0x2004], ax
mov ax, word [far_caller_2 + 4]
mov [0x200a], ax
mov ax, word [far_caller_3 + 4]
mov [0x2010], ax
mov ax, word [far_caller_4 + 4]
mov [0x2016], ax
mov ax, word [far_caller_5 + 4]
mov [0x201c], ax
;初始化用户ldt段(代码段、数据段)
mov eax, [ebp + 16]
add eax, proc_ctrl.ldt
mov dword [eax], ldt_code_low_dd
mov dword [eax + 4], ldt_code_high_dd
mov dword [eax + 8], ldt_data_low_dd
mov dword [eax + 0x0c], ldt_data_high_dd
;将用户ldt段加入gdt
call Set_LDT_sel
mov eax, [ebp + 16]
add eax, proc_ctrl.ldt_sel
mov [eax], cx
;初始化用户进程TSS页,段内所有保留位都清空
mov eax, [ebp + 16]
add eax, proc_ctrl.tss
push eax
mov ecx, 26
xor edx, edx
_init_usr_tss:
mov dword [eax + edx], 0x0
add edx, 4
loop _init_usr_tss
;逐项填写TSS段
call Alloc_sys_page ;分配用户进程使用的R0权限下的堆栈页
mov edx, eax
add edx, 4092 ;esp0指针指向页的最后
pop eax ;恢复指向tss段的首地址
mov dword [eax+0x4], edx ;esp0
mov word [eax+0x8], flat_mode_data ;ss0
mov ebx, [ebp + 12]
mov dword [eax+0x1c], ebx ;cr3
mov dword [eax+0x20], 48 ;eip
pushfd
pop ebx
mov dword [eax+0x24], ebx ;eflag
mov dword [eax+0x38], 0x2000-4 ;esp
mov dword [eax+0x4c], 0x7 ;cs(list-0,TI-1,RPL-3)
mov dword [eax+0x50], 0x0f ;ss(list-1,TI-1,RPL-3)
mov dword [eax+0x54], 0x0f ;ds(list-1,TI-1,RPL-3)
mov ebx, [ebp + 16]
add ebx, proc_ctrl.ldt_sel
mov cx, [ebx]
mov word [eax+0x60], cx ;ldt选择子
mov word [eax+0x66], 103 ;TSS段长度
;将用户tss写入gdt
call Set_TSS_sel
;修改进程状态为 正在运行
mov eax, [ebp + 16] ;进程控制段
add eax, proc_ctrl.state ;进程状态字段
mov word [eax], task_running ;进程状态字段设置为 正在运行
;将进程控制段放入进程链表
mov edx, [ebp + 16]
call mount_task_running_que
;将进程在gdt中的选择子写入进程结构进行保存
mov edx, [ebp + 16]
mov [edx + proc_ctrl.task_sel], cx
;绘制用户进程窗口
mov edx, [ebp + 16]
call draw_task_window
add esp, 28
ret
;-------------------------------------------------------------------------------
mount_task_running_que: ;将进程结构安装到运行队列中
;输入参数: edx--进程PROC_CTRL结构的偏移地址
cli ;关中断
pushad
mov eax, [SYS_PROC + proc_ctrl.pre_task] ;前一个进程结构地址
mov [eax + proc_ctrl.next_task], edx ;前一个进程的next指向新进程结构
mov [SYS_PROC + proc_ctrl.pre_task], edx ;系统进程的pre指向新进程结构
mov [edx + proc_ctrl.pre_task], eax ;新进程的pre指向前一个进程结构
mov ebx, SYS_PROC ;新进程的next指向系统进程
mov [edx + proc_ctrl.next_task], ebx
popad
sti ;开中断
ret
;-------------------------------------------------------------------------------
mount_task_run_to_pend_que: ;将进程结构从就绪队列放入暂停队列 (在这里,由于系统进程不休眠,只有两个用户进程休眠,所以下面的代码偷懒了)
;输入参数: edx--进程PROC_CTRL结构的偏移地址
cli ;关中断
pushad
;将进程结构从队列中取出
mov eax, [edx + proc_ctrl.pre_task] ;进程所在队列的前一个结构
mov ebx, [edx + proc_ctrl.next_task] ;进程所在队列的后一个结构
mov [_task_next], ebx ;记录下一个进程结构地址
mov [eax + proc_ctrl.next_task], ebx ;前一个结构的next指向后一个结构
mov [ebx + proc_ctrl.pre_task], eax ;后一个结构的pre指向前一个结构
;将进程结构放入pending队列
cmp dword [_task_pend_que], 0x0 ;暂停队列是否为空
jnz _chg_pnd_que1 ;如果包含进程结构
mov [_task_pend_que], edx ;暂定队列头部指向该进程结构
mov [edx + proc_ctrl.pre_task], edx ;该进程结构的pre指向自己
mov [edx + proc_ctrl.next_task], edx ;该进程结构的next指向自己
jmp _chg_pnd_que2 ;退出函数
_chg_pnd_que1: ;在这里,先被唤醒的放队列的前面,后被唤醒的放后面
mov eax, dword[_task_pend_que] ;eax指向暂定队列头部
mov ecx, [edx + proc_ctrl.wakeup] ;ecx指向新进程被唤醒的时刻值
cmp ecx, [eax + proc_ctrl.wakeup] ;和暂停队列头部比较唤醒时间大小
jb _insert_head ;如果暂停时间小于头部时间,就插入暂停队列头部
;插入暂停队列尾部
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向暂定队列的最后一个结构
mov [ebx + proc_ctrl.next_task], edx ;队列最后一个结构的next指向本进程结构
mov [eax + proc_ctrl.pre_task], edx ;暂定队列头部的pre指向本进程结构
mov [edx + proc_ctrl.pre_task], ebx ;本进程结构的pre指向原队列最后一个结构
mov [edx + proc_ctrl.next_task], eax ;本进程结构的next指向队列头部
jmp _chg_pnd_que2
;插入暂停队列头部
_insert_head:
mov eax, [_task_pend_que] ;eax指向暂停队列头部
mov [edx + proc_ctrl.next_task], eax ;本进程的next指向队列头部
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向暂定队列的最后一个结构
mov [edx + proc_ctrl.pre_task], ebx
mov [ebx + proc_ctrl.next_task], edx
mov [eax + proc_ctrl.pre_task], edx
mov [_task_pend_que], edx ;暂停队列头部指向本结构
_chg_pnd_que2:
popad
sti ;开中断
;跳转到下一个就绪进程执行
mov eax, [_task_next] ;下一个进程结构地址
mov [_task_now], eax ;当前进程
add eax, proc_ctrl.task_rsvr
jmp far [eax] ;跳转到新的进程执行
ret
;-------------------------------------------------------------------------------
mount_task_pend_to_run_que: ;将进程结构从暂停队列放入就绪队列(就绪队列头部永远指向系统进程)
;输入参数: edx--进程PROC_CTRL结构的偏移地址
;cli ;关中断
pushad
;先将进程结构从暂定队列取出
mov edx, [_task_pend_que] ;首先判断暂定队列是否只有一个结构
mov eax, [edx + proc_ctrl.next_task] ;eax指向暂停队列头部的下一个结构
cmp eax, edx ;如果暂停队列头部结构的next指向自己,暂停队列只有一个结构
jnz _fix_pend_que_head
xor eax, eax
mov [_task_pend_que], eax ;暂停队列头部清空
jmp _mount_to_run_que
_fix_pend_que_head: ;将暂停队列头部结构取出
mov ebx, [edx + proc_ctrl.pre_task] ;ebx指向暂停队列的尾部
mov [ebx + proc_ctrl.next_task], eax ;尾部结构的next指向原队列的第二个结构
mov [eax + proc_ctrl.pre_task], ebx ;原队列的第二个结构的pre指向队列尾部结构
mov [_task_pend_que], eax ;暂停队列头部修改为原第二个结构地址
_mount_to_run_que:
;将进程结构放入就绪队列
mov eax, SYS_PROC ;eax指向系统进程
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向就绪队列最后一个结构
mov [eax + proc_ctrl.pre_task], edx ;系统进程的pre指向该进程结构
mov [ebx + proc_ctrl.next_task], edx ;就绪队列最后一个结构的next指向该进程结构
mov [edx + proc_ctrl.pre_task], ebx ;该进程的pre指向队列原最后一个结构
mov [edx + proc_ctrl.next_task], eax ;该进程的next指向系统进程结构
popad
;sti ;开中断
ret
;-------------------------------------------------------------------------------
switch_task2: ;轮转切换当前执行的进程
mov eax, [_task_now] ;eax指向当前进程
mov ebx, [eax + proc_ctrl.next_task] ;ebx指向下一个进程
cmp eax, ebx ;是否是同一个进程
je _switch_task_ok ;如果是同一个进程,无需切换
mov [_task_now], ebx ;更新当前进程记录
add ebx, proc_ctrl.task_rsvr
jmp far [ebx] ;跳转到新的进程执行
_switch_task_ok:
ret
;-------------------------------------------------------------------------------
wakeup_task: ;检查进程休眠时间是否到时,并唤醒(在中断中处理,无需关中断)
pushad
mov eax, [_task_pend_que] ;eax指向休眠队列头部
cmp eax, 0x0 ;休眠队列是否为空
jz wakeup_task_finished ;如果为空,直接跳出
mov ebx, [sys_click] ;当前的系统时间
mov ecx, [eax + proc_ctrl.wakeup] ;ecx为进程被唤醒时间
cmp ebx, ecx ;如果系统时间大于等于进程的唤醒时间
jb wakeup_task_finished
mov edx, eax ;调用时,edx指向被调整的进程地址
call mount_task_pend_to_run_que ;将进程结构从暂定队列放入就绪队列
wakeup_task_finished:
popad
ret
;-------------------------------------------------------------------------------
draw_task_window: ;绘制用户进程窗口(窗口横梁宽度为5个点,其余都为一个点)
;输入:edx - 进程PROC_CTRL结构的偏移地址
pushad
;窗口横梁,6个点宽
xor eax, eax
mov ax, 5 ;eax高16位是y的高度
shl eax, 16
mov ax, [edx + proc_ctrl.left_y] ;eax低16位是y的值
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_x] ;ebx高16位是x的宽度
shl ebx, 16
mov bx, [edx + proc_ctrl.left_x] ;ebx低16位是x的值
mov cl, 8
call draw_rectangle ;画一个矩形
;窗口下梁,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
add ax, [edx + proc_ctrl.len_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_x]
mov cl, 8
call draw_line
;窗口左柱,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_y]
mov cl, 8
call draw_long_string
;窗口右柱,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
add ax, [edx + proc_ctrl.len_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_y]
inc bx
mov cl, 8
call draw_long_string
;窗口的退出按钮,大小为3×3的矩形
xor eax, eax
mov ax, 3 ;eax高16位是y的高度
shl eax, 16
mov ax, [edx + proc_ctrl.left_y] ;eax低16位是y的值
inc ax
xor ebx, ebx
mov bx, 3 ;ebx高16位是x的宽度
shl ebx, 16
mov bx, [edx + proc_ctrl.left_x] ;ebx低16位是x的值
add bx, [edx + proc_ctrl.len_x]
sub bx, 4
mov cl, 10 ;暗绿
call draw_rectangle ;画一个矩形
popad
ret
;-------------------------------------------------------------------------------
read_hard_disk_0: ;从硬盘读取一个逻辑扇区(平坦模型)
;EAX=逻辑扇区号
;EBX=目标缓冲区线性地址
;返回:EBX=EBX+512
cli
push eax
push ecx
push edx
push eax
mov dx,0x1f2
mov al,1
out dx,al ;读取的扇区数
inc dx ;0x1f3
pop eax
out dx,al ;LBA地址7~0
inc dx ;0x1f4
mov cl,8
shr eax,cl
out dx,al ;LBA地址15~8
inc dx ;0x1f5
shr eax,cl
out dx,al ;LBA地址23~16
inc dx ;0x1f6
shr eax,cl
or al,0xe0 ;第一硬盘 LBA地址27~24
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
.waits:
in al,dx
and al,0x88
cmp al,0x08
jnz .waits ;不忙,且硬盘已准备好数据传输
mov ecx,256 ;总共要读取的字数
mov dx,0x1f0
.readw:
in ax,dx
mov [ebx],ax
add ebx,2
loop .readw
pop edx
pop ecx
pop eax
sti
ret
;--------------------------------全局变量---------------------------------------
align 4
_task_now dd 0 ;当前工作进程控制结构地址
_task_next dd 0 ;当前工作进程的下一个结构
_task_pend_que dd 0x0 ;暂停进程队列头
_task_stop_que dd 0x0 ;停止进程队列头
_task_old dd 0 ;保存上一个进程的控制结构地址
;_task_window dd 0 ;按照顺序分配窗口(0-左下;1-右下;2-右上;左上角的窗口留给系统进程)
SYS_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
USR1_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
USR2_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
align 4
该文件包括了系统进程的创建、用户进程的安装、进程控制块链表的控制(运行链表、休眠链表)、进程窗口的绘制、硬盘扇区的读取。
Set_TSS_sel:安装TSS段;
Set_LDT_sel:安装LDT段;
Load_core_task:创建系统进程(权限0);
Load_usr_task:创建用户进程(权限3);
mount_task_running_que:将进程结构安装到运行队列中;
mount_task_run_to_pend_que:将进程结构从运行队列放入暂停队列;
mount_task_pend_to_run_que:将进程结构从暂停队列放入运行队列;
switch_task2:轮转切换当前执行的进程;
wakeup_task:检查进程休眠时间是否到时,并唤醒;
draw_task_window:绘制用户进程窗口;
read_hard_disk_0:从硬盘读取一个逻辑扇区;
代码中的SYS_PROC、USR1_PROC、USR2_PROC分别保存了系统进程、用户进程1、用户进程2的控制块。
;===============================================================================
;=== 本程序包括了进程管理的主要功能: ===
;=== 1.进程结构初始化 ===
;=== 2.进程的安装、启动、唤醒、睡眠 ===
;===============================================================================
;-------------------------------------------------------------------------------
Set_TSS_sel: ;安装TSS段
;输入参数: eax-—TSS段基地址
;输出参数: cx—-gdt中的选择子
push edx ;保存edx
xor ecx, ecx ;ecx清零
sgdt [pgdt] ;获取gdt表长度和基址
mov cx, word [pgdt] ;段界限
mov edx, dword [pgdt+2] ;段基址
inc cx ;gdt表长度
add edx, ecx ;安装地址
mov word [edx], 103 ;TSS段长度的低16位
mov word [edx+2], ax ;TSS段基址的低16位
shr eax, 16 ;TSS段基址右移16位
mov byte [edx+4], al ;TSS段基址的中8位
mov byte [edx+7], ah ;TSS段基址的高8位
mov byte [edx+5], 1_00_0_1001B ;P-1,TYPE-9(可用386TSS段)
mov byte [edx+6], 0_1_0_0_0000B ;G-0,X-1,limit-0
add word [pgdt], 8 ;gdt表长度增加8字节
lgdt [pgdt] ;重新安装gdt表到系统
pop edx ;弹出edx
ret
;-------------------------------------------------------------------------------
Set_LDT_sel: ;安装LDT段
;输入参数: eax-—LDT段基地址
;输出参数: cx—-gdt中的选择子
push edx ;保存edx
xor ecx, ecx ;ecx清零
sgdt [pgdt] ;获取gdt表长度和基址
mov cx, word [pgdt] ;段界限
mov edx, dword [pgdt+2] ;段基址
inc cx ;gdt表长度
add edx, ecx ;安装地址
mov word [edx], 15 ;LDT段长度的低16位
mov word [edx+2], ax ;LDT段基址的低16位
shr eax, 16 ;LDT段基址右移16位
mov byte [edx+4], al ;LDT段基址的中8位
mov byte [edx+7], ah ;LDT段基址的高8位
mov byte [edx+5], 1_11_0_0010B ;P-1,DPL=3,TYPE-2(LDT段)
mov byte [edx+6], 0_1_0_0_0000B ;G-0,X-1,limit-0
add word [pgdt], 8 ;gdt表长度增加8字节
lgdt [pgdt] ;重新安装gdt表到系统
pop edx ;弹出edx
ret
;-------------------------------------------------------------------------------
Load_core_task: ;创建系统进程(权限0)
pushad
;内核任务的TSS段填写,清空缓冲区,使段内所有保留位置0
mov eax, SYS_PROC + proc_ctrl.tss
mov ecx, 104
_init_tss:
mov byte [eax], 0x0
inc eax
loop _init_tss
mov eax, SYS_PROC + proc_ctrl.tss
mov ecx, cr3
mov dword [eax + 0x1c], ecx ;此处的CR3的写入必须要有,因为Set_TSS_sel不会主动加入页目录!!!
;在gdt中写入tss段描述符
call Set_TSS_sel ;安装TSS,段首地址在eax中
mov [SYS_PROC + proc_ctrl.task_sel], cx
ltr cx ;将内核任务写入系统
mov eax, SYS_PROC
mov [SYS_PROC + proc_ctrl.pre_task], eax ;系统进程的前一进程指向自己
mov [SYS_PROC + proc_ctrl.next_task], eax ;系统进程的后一进程也指向自己
;记录当前工作进程
mov eax, SYS_PROC
mov [_task_now], eax ;当前工作进程为系统进程
add eax, proc_ctrl.next_task
mov dword [eax], SYS_PROC ;系统进程控制结构的下一个进程地址 指向自己
mov eax, SYS_PROC
add eax, proc_ctrl.state
mov word [eax], task_running ;工作进程状态为 正在运行
popad
ret
;-------------------------------------------------------------------------------
Load_usr_task: ;创建用户进程(权限3)
;输入参数: eax--用户进程的起始扇区号
;输入参数: ebx--用户进程扇区个数
;输入参数: ecx--进程PROC_CTRL结构的偏移地址
;输出参数: cx—-用户进程TSS段在gdt中的选择子
push eax ;[ebp + 24] 起始扇区号
push ebx ;[ebp + 20] 扇区个数
push ecx ;[ebp + 16] 进程控制结构proc_ctrl的偏移
;用户内存区分配用户“页目录”、“页表1”、“app页”、“用户堆栈esp3”三页
call Alloc_usr_page
push eax ;[ebp + 12] 页目录页
call Alloc_usr_page
push eax ;[ebp + 8] 页表1
call Alloc_usr_page
push eax ;[ebp + 4] app页
call Alloc_usr_page
push eax ;[ebp] 用户堆栈
mov ebp, esp
;将用户页目录、页表1、app页映射到系统进程的前三页
mov eax, [ebp + 12]
or eax, 0x7
mov dword [0xffc00000], eax
mov eax, [ebp + 8]
or eax, 0x7
mov dword [0xffc00004], eax
mov eax, [ebp + 4]
or eax, 0x7
mov dword [0xffc00008], eax
;拷贝系统页目录到用户页目录
mov ecx, 1024
xor edx, edx
_dir_cpy:
mov eax, dword [0xfffff000 + edx]
mov dword [edx], eax
add edx, 4
loop _dir_cpy
;用户页目录最后一项指向自己
mov eax, [ebp + 12]
or eax, 0x7
mov dword [4092], eax
;用户页目录第一项指向页表1
mov eax, [ebp + 8]
or eax, 0x7
mov dword [0], eax
;用户页表1第一项指向用户app页(对应线性地址:0x0-0x1000)
mov eax, [ebp + 4]
or eax, 0x7
mov dword [0x1000], eax
;用户页表1第二项指向权限3堆栈(对应线性地址:0x1000-0x2000)
mov eax, [ebp]
or eax, 0x7
mov dword [0x1004], eax
;将用户进程数据从逻辑扇区拷贝到到用户app页中
mov eax, [ebp + 24]
mov ebx, 0x2000
mov ecx, [ebp + 20]
_cpy_disk:
call read_hard_disk_0
inc eax
loop _cpy_disk
;将调用门信息写入用户进程
mov ax, word [far_caller_1 + 4]
mov [0x2004], ax
mov ax, word [far_caller_2 + 4]
mov [0x200a], ax
mov ax, word [far_caller_3 + 4]
mov [0x2010], ax
mov ax, word [far_caller_4 + 4]
mov [0x2016], ax
mov ax, word [far_caller_5 + 4]
mov [0x201c], ax
;初始化用户ldt段(代码段、数据段)
mov eax, [ebp + 16]
add eax, proc_ctrl.ldt
mov dword [eax], ldt_code_low_dd
mov dword [eax + 4], ldt_code_high_dd
mov dword [eax + 8], ldt_data_low_dd
mov dword [eax + 0x0c], ldt_data_high_dd
;将用户ldt段加入gdt
call Set_LDT_sel
mov eax, [ebp + 16]
add eax, proc_ctrl.ldt_sel
mov [eax], cx
;初始化用户进程TSS页,段内所有保留位都清空
mov eax, [ebp + 16]
add eax, proc_ctrl.tss
push eax
mov ecx, 26
xor edx, edx
_init_usr_tss:
mov dword [eax + edx], 0x0
add edx, 4
loop _init_usr_tss
;逐项填写TSS段
call Alloc_sys_page ;分配用户进程使用的R0权限下的堆栈页
mov edx, eax
add edx, 4092 ;esp0指针指向页的最后
pop eax ;恢复指向tss段的首地址
mov dword [eax+0x4], edx ;esp0
mov word [eax+0x8], flat_mode_data ;ss0
mov ebx, [ebp + 12]
mov dword [eax+0x1c], ebx ;cr3
mov dword [eax+0x20], 48 ;eip
pushfd
pop ebx
mov dword [eax+0x24], ebx ;eflag
mov dword [eax+0x38], 0x2000-4 ;esp
mov dword [eax+0x4c], 0x7 ;cs(list-0,TI-1,RPL-3)
mov dword [eax+0x50], 0x0f ;ss(list-1,TI-1,RPL-3)
mov dword [eax+0x54], 0x0f ;ds(list-1,TI-1,RPL-3)
mov ebx, [ebp + 16]
add ebx, proc_ctrl.ldt_sel
mov cx, [ebx]
mov word [eax+0x60], cx ;ldt选择子
mov word [eax+0x66], 103 ;TSS段长度
;将用户tss写入gdt
call Set_TSS_sel
;修改进程状态为 正在运行
mov eax, [ebp + 16] ;进程控制段
add eax, proc_ctrl.state ;进程状态字段
mov word [eax], task_running ;进程状态字段设置为 正在运行
;将进程控制段放入进程链表
mov edx, [ebp + 16]
call mount_task_running_que
;将进程在gdt中的选择子写入进程结构进行保存
mov edx, [ebp + 16]
mov [edx + proc_ctrl.task_sel], cx
;绘制用户进程窗口
mov edx, [ebp + 16]
call draw_task_window
add esp, 28
ret
;-------------------------------------------------------------------------------
mount_task_running_que: ;将进程结构安装到运行队列中
;输入参数: edx--进程PROC_CTRL结构的偏移地址
cli ;关中断
pushad
mov eax, [SYS_PROC + proc_ctrl.pre_task] ;前一个进程结构地址
mov [eax + proc_ctrl.next_task], edx ;前一个进程的next指向新进程结构
mov [SYS_PROC + proc_ctrl.pre_task], edx ;系统进程的pre指向新进程结构
mov [edx + proc_ctrl.pre_task], eax ;新进程的pre指向前一个进程结构
mov ebx, SYS_PROC ;新进程的next指向系统进程
mov [edx + proc_ctrl.next_task], ebx
popad
sti ;开中断
ret
;-------------------------------------------------------------------------------
mount_task_run_to_pend_que: ;将进程结构从就绪队列放入暂停队列 (在这里,由于系统进程不休眠,只有两个用户进程休眠,所以下面的代码偷懒了)
;输入参数: edx--进程PROC_CTRL结构的偏移地址
cli ;关中断
pushad
;将进程结构从队列中取出
mov eax, [edx + proc_ctrl.pre_task] ;进程所在队列的前一个结构
mov ebx, [edx + proc_ctrl.next_task] ;进程所在队列的后一个结构
mov [_task_next], ebx ;记录下一个进程结构地址
mov [eax + proc_ctrl.next_task], ebx ;前一个结构的next指向后一个结构
mov [ebx + proc_ctrl.pre_task], eax ;后一个结构的pre指向前一个结构
;将进程结构放入pending队列
cmp dword [_task_pend_que], 0x0 ;暂停队列是否为空
jnz _chg_pnd_que1 ;如果包含进程结构
mov [_task_pend_que], edx ;暂定队列头部指向该进程结构
mov [edx + proc_ctrl.pre_task], edx ;该进程结构的pre指向自己
mov [edx + proc_ctrl.next_task], edx ;该进程结构的next指向自己
jmp _chg_pnd_que2 ;退出函数
_chg_pnd_que1: ;在这里,先被唤醒的放队列的前面,后被唤醒的放后面
mov eax, dword[_task_pend_que] ;eax指向暂定队列头部
mov ecx, [edx + proc_ctrl.wakeup] ;ecx指向新进程被唤醒的时刻值
cmp ecx, [eax + proc_ctrl.wakeup] ;和暂停队列头部比较唤醒时间大小
jb _insert_head ;如果暂停时间小于头部时间,就插入暂停队列头部
;插入暂停队列尾部
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向暂定队列的最后一个结构
mov [ebx + proc_ctrl.next_task], edx ;队列最后一个结构的next指向本进程结构
mov [eax + proc_ctrl.pre_task], edx ;暂定队列头部的pre指向本进程结构
mov [edx + proc_ctrl.pre_task], ebx ;本进程结构的pre指向原队列最后一个结构
mov [edx + proc_ctrl.next_task], eax ;本进程结构的next指向队列头部
jmp _chg_pnd_que2
;插入暂停队列头部
_insert_head:
mov eax, [_task_pend_que] ;eax指向暂停队列头部
mov [edx + proc_ctrl.next_task], eax ;本进程的next指向队列头部
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向暂定队列的最后一个结构
mov [edx + proc_ctrl.pre_task], ebx
mov [ebx + proc_ctrl.next_task], edx
mov [eax + proc_ctrl.pre_task], edx
mov [_task_pend_que], edx ;暂停队列头部指向本结构
_chg_pnd_que2:
popad
sti ;开中断
;跳转到下一个就绪进程执行
mov eax, [_task_next] ;下一个进程结构地址
mov [_task_now], eax ;当前进程
add eax, proc_ctrl.task_rsvr
jmp far [eax] ;跳转到新的进程执行
ret
;-------------------------------------------------------------------------------
mount_task_pend_to_run_que: ;将进程结构从暂停队列放入就绪队列(就绪队列头部永远指向系统进程)
;输入参数: edx--进程PROC_CTRL结构的偏移地址
;cli ;关中断
pushad
;先将进程结构从暂定队列取出
mov edx, [_task_pend_que] ;首先判断暂定队列是否只有一个结构
mov eax, [edx + proc_ctrl.next_task] ;eax指向暂停队列头部的下一个结构
cmp eax, edx ;如果暂停队列头部结构的next指向自己,暂停队列只有一个结构
jnz _fix_pend_que_head
xor eax, eax
mov [_task_pend_que], eax ;暂停队列头部清空
jmp _mount_to_run_que
_fix_pend_que_head: ;将暂停队列头部结构取出
mov ebx, [edx + proc_ctrl.pre_task] ;ebx指向暂停队列的尾部
mov [ebx + proc_ctrl.next_task], eax ;尾部结构的next指向原队列的第二个结构
mov [eax + proc_ctrl.pre_task], ebx ;原队列的第二个结构的pre指向队列尾部结构
mov [_task_pend_que], eax ;暂停队列头部修改为原第二个结构地址
_mount_to_run_que:
;将进程结构放入就绪队列
mov eax, SYS_PROC ;eax指向系统进程
mov ebx, [eax + proc_ctrl.pre_task] ;ebx指向就绪队列最后一个结构
mov [eax + proc_ctrl.pre_task], edx ;系统进程的pre指向该进程结构
mov [ebx + proc_ctrl.next_task], edx ;就绪队列最后一个结构的next指向该进程结构
mov [edx + proc_ctrl.pre_task], ebx ;该进程的pre指向队列原最后一个结构
mov [edx + proc_ctrl.next_task], eax ;该进程的next指向系统进程结构
popad
;sti ;开中断
ret
;-------------------------------------------------------------------------------
switch_task2: ;轮转切换当前执行的进程
mov eax, [_task_now] ;eax指向当前进程
mov ebx, [eax + proc_ctrl.next_task] ;ebx指向下一个进程
cmp eax, ebx ;是否是同一个进程
je _switch_task_ok ;如果是同一个进程,无需切换
mov [_task_now], ebx ;更新当前进程记录
add ebx, proc_ctrl.task_rsvr
jmp far [ebx] ;跳转到新的进程执行
_switch_task_ok:
ret
;-------------------------------------------------------------------------------
wakeup_task: ;检查进程休眠时间是否到时,并唤醒(在中断中处理,无需关中断)
pushad
mov eax, [_task_pend_que] ;eax指向休眠队列头部
cmp eax, 0x0 ;休眠队列是否为空
jz wakeup_task_finished ;如果为空,直接跳出
mov ebx, [sys_click] ;当前的系统时间
mov ecx, [eax + proc_ctrl.wakeup] ;ecx为进程被唤醒时间
cmp ebx, ecx ;如果系统时间大于等于进程的唤醒时间
jb wakeup_task_finished
mov edx, eax ;调用时,edx指向被调整的进程地址
call mount_task_pend_to_run_que ;将进程结构从暂定队列放入就绪队列
wakeup_task_finished:
popad
ret
;-------------------------------------------------------------------------------
draw_task_window: ;绘制用户进程窗口(窗口横梁宽度为5个点,其余都为一个点)
;输入:edx - 进程PROC_CTRL结构的偏移地址
pushad
;窗口横梁,6个点宽
xor eax, eax
mov ax, 5 ;eax高16位是y的高度
shl eax, 16
mov ax, [edx + proc_ctrl.left_y] ;eax低16位是y的值
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_x] ;ebx高16位是x的宽度
shl ebx, 16
mov bx, [edx + proc_ctrl.left_x] ;ebx低16位是x的值
mov cl, 8
call draw_rectangle ;画一个矩形
;窗口下梁,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
add ax, [edx + proc_ctrl.len_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_x]
mov cl, 8
call draw_line
;窗口左柱,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_y]
mov cl, 8
call draw_long_string
;窗口右柱,1个点宽
xor eax, eax
mov ax, [edx + proc_ctrl.left_x]
add ax, [edx + proc_ctrl.len_x]
shl eax, 16
mov ax, [edx + proc_ctrl.left_y]
xor ebx, ebx
mov bx, [edx + proc_ctrl.len_y]
inc bx
mov cl, 8
call draw_long_string
;窗口的退出按钮,大小为3×3的矩形
xor eax, eax
mov ax, 3 ;eax高16位是y的高度
shl eax, 16
mov ax, [edx + proc_ctrl.left_y] ;eax低16位是y的值
inc ax
xor ebx, ebx
mov bx, 3 ;ebx高16位是x的宽度
shl ebx, 16
mov bx, [edx + proc_ctrl.left_x] ;ebx低16位是x的值
add bx, [edx + proc_ctrl.len_x]
sub bx, 4
mov cl, 10 ;暗绿
call draw_rectangle ;画一个矩形
popad
ret
;-------------------------------------------------------------------------------
read_hard_disk_0: ;从硬盘读取一个逻辑扇区(平坦模型)
;EAX=逻辑扇区号
;EBX=目标缓冲区线性地址
;返回:EBX=EBX+512
cli
push eax
push ecx
push edx
push eax
mov dx,0x1f2
mov al,1
out dx,al ;读取的扇区数
inc dx ;0x1f3
pop eax
out dx,al ;LBA地址7~0
inc dx ;0x1f4
mov cl,8
shr eax,cl
out dx,al ;LBA地址15~8
inc dx ;0x1f5
shr eax,cl
out dx,al ;LBA地址23~16
inc dx ;0x1f6
shr eax,cl
or al,0xe0 ;第一硬盘 LBA地址27~24
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
.waits:
in al,dx
and al,0x88
cmp al,0x08
jnz .waits ;不忙,且硬盘已准备好数据传输
mov ecx,256 ;总共要读取的字数
mov dx,0x1f0
.readw:
in ax,dx
mov [ebx],ax
add ebx,2
loop .readw
pop edx
pop ecx
pop eax
sti
ret
;--------------------------------全局变量---------------------------------------
align 4
_task_now dd 0 ;当前工作进程控制结构地址
_task_next dd 0 ;当前工作进程的下一个结构
_task_pend_que dd 0x0 ;暂停进程队列头
_task_stop_que dd 0x0 ;停止进程队列头
_task_old dd 0 ;保存上一个进程的控制结构地址
;_task_window dd 0 ;按照顺序分配窗口(0-左下;1-右下;2-右上;左上角的窗口留给系统进程)
SYS_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
USR1_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
USR2_PROC:
istruc proc_ctrl
at proc_ctrl.num, resw 0
at proc_ctrl.state, resw 0
at proc_ctrl.wakeup, resd 0
at proc_ctrl.pre_task, resd 0
at proc_ctrl.next_task, resd 0
at proc_ctrl.task_rsvr, resd 0
at proc_ctrl.task_sel, resw 0
at proc_ctrl.ldt_rsvr, resd 0
at proc_ctrl.ldt_sel, resw 0
at proc_ctrl.ldt, times 16 db 0
at proc_ctrl.tss, times 104 db 0
at proc_ctrl.cmd, times 8 db 0
at proc_ctrl.sys_page, resd 0
at proc_ctrl.usr_page, times 8 dd 0
at proc_ctrl.left_x, resw 0
at proc_ctrl.left_y, resw 0
at proc_ctrl.len_x, resw 0
at proc_ctrl.len_y, resw 0
iend
align 4
相关文章推荐
- 系统的简单注解 - 5 02_mouse.asm文件
- 系统的简单注解 - 4 01_interrupt.asm文件
- 系统的简单注解 - 2 core.asm文件
- 系统的简单注解 - 13 10_keyboard.asm文件
- 系统的简单注解 - 6 03_timer.asm文件
- 系统的简单注解 - 9 06_color.asm文件
- 系统的简单注解 - 11 08_bs16.asm文件
- 系统的简单注解 - 12 09_font.asm
- NTFS与FAT32文件系统互换的简单的办法
- Linux下简单配置SAMBA服务,实现与Windows系统文件共享.
- 数据库从文件系统转移至ASM实验记录
- 一个简单二级文件管理系统
- 简单说点对文件系统、分层驱动、文件读写的理解
- Linux下共享文件系统文件传输的简单设计(转载)
- 操作系统课程设计--简单文件系统的实现
- 利用RMAN将数据库从文件系统迁移到ASM
- 利用fsockopen制作简单远程文件监控系统
- 简单介绍Windows Mobile 05 中的一些重要的系统文件
- 文件系统的简单操作