一个用x86汇编编写的、页式管理、图形化的CS -- Core篇

       本篇将介绍CS的核心部分代码。核心部分实现的主要功能如下:

  1. 在gdt中安装四个调用门接口,分别是:显示一个点、用户进程sleep、画矩形、获取鼠标在界面上的点击信息;
  2. 启动中断功能,一共安装了两个中断:时钟中断、鼠标中断;
  3. 将核心作为一个单独的进程,写入当前进程寄存器;
  4. 启动两个用户进程;
  5. 核心进入循环过程:显示鼠标的移动、在界面的最上面一行显示一个不断移动的直线;
  6. 使用两个双向链表进行进程的控制:就绪链表、暂停链表。其中,就绪链表中的进程每40毫秒切换一次;用户进程使用sleep调用时,进入暂停链表。sleep到点后,用户进程重新进入就绪链表;
  7. 整个系统的内存分布使用扁平模式;
  8. 用户进程的安装由Load_usr_task函数负责;

      具体的core代码如下所示:

;===============================================================================
;=== 本程序为系统Core程序,其主要功能有:                                    ===
;=== 1.在gdt中安装四个调用门                                                 ===
;=== 2.安装core进程                                                          === 
;=== 3.安装两个用户进程                                                      ===
;=== 4.启动中断功能                                                          ===
;=== 5.用户进程和系统进程以40ms的间隔切换                                    ===
;=== 6.两个进程分别在界面上显示图形                                          ===
;=== 7.通过鼠标的点击控制用户进程图形的显示                                  ===
;===============================================================================
;===============================================================================
;===                             该处用于保存常量                            ===
;===============================================================================
	 flat_4gb_code_seg_sel    equ 0x0008          ;平坦模式的代码段选择子
	 flat_mode_code           equ 0x0008          ;平坦模式的代码段选择子 
	 flat_mode_data           equ 0x0010          ;平坦模式的数据段选择子
	 
;-------------------------------------------------------------------------------
	 show_mem_addr            equ 0xc00b8000      ;文本显示区域的起始地址
     pic_mem_addr             equ 0xc00a0000      ;图形显示区域的起始地址	 
	 gdt_base_address         equ 0xc0008000      ;gdt表的虚拟地址   
     idt_linear_address       equ 0xc0019000      ;中断描述符表的线性基地址(100K处)	
     mouse_buf_addr           equ 0xc0020000      ;存放鼠标数据的缓冲区基地址      
     mouse_buf_end            equ 8192            ;存放鼠标数据的缓冲区大小(一共8K)		 
	 
;-------------------------------------------------------------------------------
     ldt_code_high_dd         equ 0x00cff800      ;常数,ldt表中代码段的高双字 base-0x0;TYPY-8 只执行;P-1;DPL-3;DT-1;G-1;D-1;limit-0xf;base-0;
	 ldt_code_low_dd          equ 0x0000ffff      ;常数,ldt表中代码段的低双字 limit-0xffff;base-0x0;
	 ldt_data_high_dd         equ 0x00cff200      ;常数,ldt表中数据段的高双字 base-0x0;TYPY-2 读/写;P-1;DPL-3;DT-1;G-1;D-1;limit-0xf;base-0;
	 ldt_data_low_dd          equ 0x0000ffff      ;常数,ldt表中数据段的低双字 limit-0xffff;base-0x0;     

;-------------------------------------------------------------------------------
     task_running            equ 0xa5a5           ;常数,表示进程正在运行
     task_spending           equ 0xaaaa           ;常数,表示进程暂定运行
     task_closed             equ 0x5555           ;常数,表示进程已经停止运行	 
	 
;-------------------------------------------------------------------------------	 
     ;进程控制管理结构。还是使用双向链表便于查找
	 struc proc_ctrl  
      .num:        resw    1                      ;进程编号
      .state:      resw    1                      ;当前状态
      .wakeup:     resd    1                      ;进程休眠的截止时间(ticks)
      .pre_task:   resd    1                      ;上一个进程控制结构的地址
      .next_task:  resd    1                      ;下一个进程控制结构的地址      
	  .task_rsvr:  resd    1                      ;保留
	  .task_sel:   resw    1                      ;进程在gdt中的选择子
      .ldt_rsvr:   resd    1                      ;保留
      .ldt_sel:    resw    1                      ;ldt在gdt中的选择子
      .ldt:        resb    16                     ;任务对应的ldt段
      .tss:	       resb    104                    ;任务对应的tss段
      .cmd         resb    8                      ;命令缓冲区(这里主要用于鼠标点击动作)
     endstruc  
	 
;===============================================================================
;===                            该处开始Core代码                             ===
;===============================================================================
SECTION  core  vstart=0xc0010000
	 [bits 32]

;-------------------------------------------------------------------------------
     call Set_color_palette             ;初始化调色板
	 
;-------------------------------------------------------------------------------
     ;安装画点调用接口	 
	 mov eax, draw_point
	 mov ebx, flat_mode_code
	 call Set_gate_sel
	 mov word [far_caller_1 + 4], cx    ;保存远程调用的选择子

	 ;图形显示测试
	 mov eax, 0
	 mov ebx, 6                         ;第0行第6个点显示亮红
     mov cl, 1
	 call far [far_caller_1]

;-------------------------------------------------------------------------------
     ;安装sleep调用接口     
	 mov eax, task_sleep
     mov ebx, flat_mode_code
     call Set_gate_sel
     mov word [far_caller_2 + 4], cx    ;保存远程调用的选择子

;-------------------------------------------------------------------------------
	 ;图形显示测试
	 mov eax, 0
	 mov ebx, 8                         ;第0行第8个点显示亮蓝
     mov cl, 4
	 call far [far_caller_1]

;-------------------------------------------------------------------------------	 
     ;安装画矩形调用接口	 
     mov eax, draw_rectangle
     mov ebx, flat_mode_code
     call Set_gate_sel
     mov word [far_caller_3 + 4], cx    ;保存远程调用的选择子	 

;-------------------------------------------------------------------------------	 
     ;安装获取命令字调用接口	 
     mov eax, get_cmd
     mov ebx, flat_mode_code
     call Set_gate_sel
     mov word [far_caller_4 + 4], cx    ;保存远程调用的选择子	 
	 
;-------------------------------------------------------------------------------
     ;启动中断功能
	 call interrupt_init

;-------------------------------------------------------------------------------
	 ;内核任务的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	    ;工作进程状态为 正在运行

;-------------------------------------------------------------------------------
	 ;创建用户任务1
     mov eax, 100                       ;用户进程代码起始扇区号
     mov ebx, 8                         ;用户进程代码扇区个数
     mov ecx, USR1_PROC	                ;用户进程控制模块proc_ctrl的偏移地址
     call Load_usr_task
	 mov [USR1_PROC + proc_ctrl.task_sel], cx   

     ;如果用户任务正常返回,显示亮点
	 mov eax, 0 
	 mov ebx, 10                           ;第0行第10个点显示亮绿
     mov cl, 2
	 call far [far_caller_1]

	 ;创建用户任务2
     mov eax, 200                       ;用户进程代码起始扇区号
     mov ebx, 8                         ;用户进程代码扇区个数
     mov ecx, USR2_PROC	                ;用户进程控制模块proc_ctrl的偏移地址
     call Load_usr_task
	 mov [USR2_PROC + proc_ctrl.task_sel], cx   	 
	 
     ;如果用户任务正常返回,显示亮点
	 mov eax, 0 
	 mov ebx, 12                           ;第0行第12个点显示亮黄
     mov cl, 3
	 call far [far_caller_1]	 
	 
;-------------------------------------------------------------------------------
     ;安装实时时钟中断
     call install_0x20_interrupt
	 
;-------------------------------------------------------------------------------
     ;安装鼠标中断
     call install_0x74_interrupt

     ;启动鼠标
     call enable_mouse	 
	 
	 ;启动用户进程
     mov eax, USR1_PROC
     mov [_task_now], eax                 ;当前执行进程为用户进程
     jmp far [USR1_PROC + proc_ctrl.task_rsvr];启动用户进程
	 	 
;-------------------------------------------------------------------------------         
_sleep:
     call move_mouse                       ;处理鼠标动作
     call move_point                       ;显示一个移动的亮点
	 hlt
	 jmp _sleep

;-------------------------------------------------------------------------------
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

;-------------------------------------------------------------------------------
make_gate_descriptor:                   ;构造门的描述符(调用门等)
										;输入:EAX=门代码在段内偏移地址
										;       BX=门代码所在段的选择子 
										;       CX=段类型及属性等(各属
										;          性位都在原始位置)
										;返回:EDX:EAX=完整的描述符
	 push ebx
	 push ecx
  
	 mov edx,eax
	 and edx,0xffff0000                 ;得到偏移地址高16位 
	 or dx,cx                           ;组装属性部分到EDX
   
	 and eax,0x0000ffff                 ;得到偏移地址低16位 
	 shl ebx,16                          
	 or eax,ebx                         ;组装段选择子部分
  
	 pop ecx
	 pop ebx
  
	 ret

;-------------------------------------------------------------------------------
Set_gate_sel:                             ;安装系统调用门
                                          ;输入参数: eax-—offset, ebx-—sector
                                          ;输出参数: 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], ax                    ;低16位offset
     shr eax, 16
     mov word [edx+6], ax                  ;高16位offset
     mov word [edx+2], bx                  ;安装Selecter
     mov word [edx+4], 0x0ec00             ;安装属性。P-1,DPL-3,TYPE-12
     add word [pgdt], 8                    ;gdt表长度增加8字节
     lgdt [pgdt]                           ;重新安装gdt表到系统

     pop edx                               ;弹出edx
	 ret 	

;-------------------------------------------------------------------------------
Alloc_sys_page:                          ;分配一页系统内存(从128K-640K处,都是可分配系统页)
                                         ;输入参数: 无
                                         ;输出参数: eax—-系统页的线性地址(返回0表示没有系统内存了)
	
     mov eax, dword [sys_mem_addr]        ;获取未分配的页线性地址
     add dword [sys_mem_addr], 0x1000
     ret

;-------------------------------------------------------------------------------
Alloc_usr_page:                          ;分配一页用户内存(1M-2M,都是可分配用户页)
                                         ;输入参数: 无
                                         ;输出参数: eax—-用户页的硬件地址(返回0表示没有用户内存了)
	
     mov eax, dword [usr_page_addr]       ;获取未分配的页硬件地址
     add dword [usr_page_addr], 0x1000    ;计算下一页硬件地址
     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
	 
     ;初始化用户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], 24                  ;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
	 	 
	 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 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指向队列头部
     
_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:	                              ;检查进程休眠时间是否到时,并唤醒(在中断中处理,无需关中断)

     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:
     ret	 
	 
;-------------------------------------------------------------------------------
draw_point:                               ;画点 
										  ;EAX=Y值
										  ;EBX=X值
										  ;CL=颜色
     pushad

     xor edx, edx                         ;edx清零,为乘法做准备
     push ebx
     mov ebx, 320
     mul ebx                              ;Y乘以320
     pop ebx
     add eax, ebx                         ;结果再加上X,得到点在图形缓存中的偏移
     mov [pic_mem_addr + eax], cl         ;写入点颜色
	 
     popad
			  
     retf   
	 
;-------------------------------------------------------------------------------
draw_line:                                ;画横线
										  ;EAX-低16位为起点Y值,高16位为起点X的值
										  ;EBX-横线长度
										  ;CL=颜色	 
     push eax
     push ebx
     push edx
     mov edx, eax
     and eax, 0x0000ffff
     push eax                             ;记录Y值,[ebp+8]
     shr edx, 16
     push edx                             ;记录X值,[ebp+4]
     push ebx                             ;记录长度,[ebp]
     mov ebp, esp
	 
     xor edx, edx	 
	 mov eax, [ebp+8]
     mov ebx, 320
     mul ebx
     mov ebx, [ebp+4]
     mov edx, [ebp]
_dr_line:
     mov [pic_mem_addr + eax + ebx], cl
     inc ebx
     dec edx
     cmp edx, 0
     ja _dr_line
	 
     add esp, 12                          ;修正堆栈指针
     pop edx
     pop ebx
     pop eax	 
     ret
										  
;-------------------------------------------------------------------------------
draw_rectangle:                           ;画矩形
										  ;EAX-低16位为Y值,高16位为Y的高度
										  ;EBX-低16位为X值,高16位为X的宽度
										  ;CL=颜色
     pushad

	 mov edx, eax
     and eax, 0x0000ffff
     push eax                             ;Y值[ebp+12]
     shr edx, 16
     push edx                             ;Y的高度[ebp+8]
     mov edx, ebx
     and ebx, 0x0000ffff                  
     push ebx                             ;X值[ebp+4]
     shr edx, 16
     push edx                             ;X的宽度[ebp]
	 mov ebp, esp 

	 mov eax, [ebp+4]
     shl eax, 16
     mov ebx, [ebp+12]
     or eax, ebx
	 mov ebx, [ebp]
     mov edx, [ebp+8]
_drw_rectangle:
     call draw_line
	 inc eax
	 dec edx
     cmp edx, 0
     ja _drw_rectangle
	 
	 add esp, 16
     popad
     retf	 

;-------------------------------------------------------------------------------
get_cmd:                                    ;获取命令
                                            ;输出参数:al-cmd的值
     push ebx
	 mov ebx, [_task_now]                   ;当前进程控制结构
     add ebx, proc_ctrl.cmd
     mov al, [ebx]
     mov byte [ebx], 0
     pop ebx
     retf
	 
;-------------------------------------------------------------------------------
task_close:                                 ;关闭用户进程,回到系统进程
                                            ;输入参数: eax--用户进程的编号 
	 ;iretd
     pushad 
	 
     mov eax, [_task_now]                   ;当前进程控制结构
     add eax, proc_ctrl.state
     mov word [eax], task_closed            ;进程状态为 退出
     
     popad
     retf

;-------------------------------------------------------------------------------
task_sleep:                                 ;用户进程休眠
                                            ;输入参数: eax--休眠时间(10毫秒的倍数)
     pushad
     
	 mov edx, [_task_now]                   ;edx指向当前进程
	 mov ebx, dword [sys_click]             ;当前的ticks
     add ebx, eax                           ;增加休眠的ticks
     mov [edx + proc_ctrl.wakeup], ebx      ;休眠截止时间	 
	 call mount_task_run_to_pend_que        ;将进程放入暂定队列
	 
     popad
     retf	 

;-------------------------------------------------------------------------------
interrupt_init:                             ;关闭用户进程,回到系统进程

         ;前20个向量是处理器异常使用的
         mov eax,general_exception_handler  ;门代码在段内偏移地址
         mov bx,flat_4gb_code_seg_sel       ;门代码所在段的选择子
         mov cx,0x8e00                      ;32位中断门,0特权级
         call make_gate_descriptor

         mov ebx,idt_linear_address         ;中断描述符表的线性地址
         xor esi,esi
_idt0:
         mov [ebx+esi*8],eax
         mov [ebx+esi*8+4],edx
         inc esi
         cmp esi,19                         ;安装前20个异常中断处理过程
         jle _idt0

         ;其余为保留或硬件使用的中断向量
         mov eax,general_interrupt_handler  ;门代码在段内偏移地址
         mov bx,flat_4gb_code_seg_sel       ;门代码所在段的选择子
         mov cx,0x8e00                      ;32位中断门,0特权级
         call make_gate_descriptor

         mov ebx,idt_linear_address         ;中断描述符表的线性地址
_idt1:
         mov [ebx+esi*8],eax
         mov [ebx+esi*8+4],edx
         inc esi
         cmp esi,255                        ;安装普通的中断处理过程
         jle _idt1
 
	     ;准备开放中断
         mov word [pidt],256*8-1            ;IDT的界限
         mov dword [pidt+2],idt_linear_address
         lidt [pidt]                        ;加载中断描述符表寄存器IDTR
	 
	     ;设置8259A中断控制器
         mov al,0x11
         out 0x20,al                        ;ICW1:边沿触发/级联方式
         mov al,0x20                        ;设置主片的8个中断号从0x20开始
         out 0x21,al                        ;ICW2:起始中断向量
         mov al,0x04
         out 0x21,al                        ;ICW3:从片级联到IR2
         mov al,0x01
         out 0x21,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI

         mov al,0x11
         out 0xa0,al                        ;ICW1:边沿触发/级联方式
         mov al,0x70                        ;设置从片的8个中断号从0x70开始
         out 0xa1,al                        ;ICW2:起始中断向量
         mov al,0x04
         out 0xa1,al                        ;ICW3:从片级联到IR2
         mov al,0x01
         out 0xa1,al                        ;ICW4:非总线缓冲,全嵌套,正常EOI

         sti                                ;开放硬件中断
		 
		 ret

;-------------------------------------------------------------------------------
general_interrupt_handler:                  ;通用的中断处理过程
         push eax
          
         mov al,0x20                        ;中断结束命令EOI 
         out 0xa0,al                        ;向从片发送 
         out 0x20,al                        ;向主片发送
         
         pop eax
          
         iretd

;-------------------------------------------------------------------------------
general_exception_handler:                  ;通用的异常处理过程

         mov byte [show_mem_addr+1600], '!'
         mov byte [show_mem_addr+1601], 0x7
         
         hlt		 

;-------------------------------------------------------------------------------
rtm_0x20_interrupt_handle:                  ;实时时钟中断处理过程

     pushad
		 
     mov al,0x60                        ;中断结束命令EOI
     out 0x20,al                        ;向8259A主片发送

     mov eax, [sys_click]
     inc eax                            ;时钟click增加 
     mov [sys_click], eax
     push eax
	 call wakeup_task                   ;尝试唤醒暂停的进程
     pop eax		 
     test eax, 0x03                     ;每中断4次就切换一次进程(4×10ms=40ms)
     jz _time_to_swicth                 ;到了40ms,进程切换
    
     popad
     iretd 

_time_to_swicth:
     call switch_task2
         
     popad
     iretd
 
;-------------------------------------------------------------------------------
install_0x20_interrupt:                      ;安装0x20号中断(实时时钟)
	 
         cli	                              ;关中断
	 
         sidt [pidt]	                      ;取idt段地址
	 
         ;设置实时时钟中断处理过程
         mov eax, rtm_0x20_interrupt_handle   ;门代码在段内偏移地址
         mov bx, flat_4gb_code_seg_sel        ;门代码所在段的选择子
         mov cx, 0x8e00                       ;32位中断门,0特权级
         call make_gate_descriptor

         mov ebx, [pidt + 2]                  ;中断描述符表的线性地址
         mov [ebx + 0x20*8], eax              ;中断描述符低32位
         mov [ebx + 0x20*8 + 4], edx     	  ;中断描述符高32位
         
         lidt [pidt]                          ;重新加载中断描述符表寄存器IDTR	 
	 
         ;设置计时时钟的中断频率
         mov al,34h                           ;设控制字值
         out 43h,al                           ;写控制字到控制字寄存器
         mov ax,1193182/100                   ;每秒100次中断(10ms一次)
         out 40h,al                           ;写计数器0的低字节
         mov al,ah                            ;AL=AH
         out 40h,al                           ;写计数器0的高字节         	 

         in al,0x21                           ;读8259主片的IMR寄存器
         and al,0xfe                          ;清除bit 0(计时器)
         out 0x21,al                          ;写回此寄存器
		 
         sti                                  ;开中断
	 
         ret
		 
;-------------------------------------------------------------------------------
rtm_0x74_interrupt_handle:                  ;实时时钟中断处理过程

         pushad

         mov al,0x64                        ;中断结束命令EOI
         out 0xa0,al                        ;向8259A从片发送
         mov al,0x62
         out 0x20,al                        ;向8259A主片发送

         mov ebx, [mouse_buf_wpnt]          ;写偏移
		 
         in al, 0x60                        ;获取鼠标数据
         cmp al, 0xfa                       ;判断是否是标志字0xfa
         jnz _data_ok                       ;如果不是
		 mov edx, [mouse_enabled]           ;再判断是否鼠标已经启动成功
         cmp edx, 0x0                       ;是否已经启动成功
		 jnz _data_ok                       ;已经启动成功
         mov dword [mouse_enabled], 0x55    ;确实是启动成功标志,设置启动成功标志,跳转出去
         jmp _out		 

_data_ok:         
         ;将收到的数据放入缓冲区
         mov [mouse_buf_addr + ebx], al     ;数据写入鼠标缓冲区
         inc ebx                            ;写指针加一
         cmp ebx, mouse_buf_end             ;判断写指针的位置
         jb _out      		                ;如果未到了缓冲区尾部,结束
         xor ebx, ebx                       ;已到缓冲区尾部,写指针翻转
		 
_out:		 
         mov [mouse_buf_wpnt], ebx          ;保存新的写指针
		 popad

         iretd

;-------------------------------------------------------------------------------
install_0x74_interrupt:                       ;安装0x74号中断(鼠标)
	 
         cli	                              ;关中断
	 
         sidt [pidt]	                      ;取idt段地址
	 
         ;设置实时时钟中断处理过程
         mov eax, rtm_0x74_interrupt_handle   ;门代码在段内偏移地址
         mov bx, flat_4gb_code_seg_sel        ;门代码所在段的选择子
         mov cx, 0x8e00                       ;32位中断门,0特权级
         call make_gate_descriptor

         mov ebx, [pidt + 2]                  ;中断描述符表的线性地址
         mov [ebx + 0x74*8], eax              ;中断描述符低32位
         mov [ebx + 0x74*8 + 4], edx     	  ;中断描述符高32位
         
         lidt [pidt]                          ;重新加载中断描述符表寄存器IDTR	 
	 
         ;打开鼠标中断在MASK寄存器中的对应位 
         in al,0xa1                           ;读8259从片的IMR寄存器
         and al,0xf7                          ;清除bit 0(此位连接鼠标)
         out 0xa1,al                          ;写回此寄存器
         
         ;配置鼠标相关寄存器
	     call init_keyboard
		 
         sti                                  ;开中断
	 
         ret
		 
;-------------------------------------------------------------------------------
init_keyboard:                              ;初始化鼠标相关寄存器
_check1:
         in al,0x64                         ;键盘缓冲区状态
         and al, 0x02
         jne _check1
		 
         mov al, 0x60
         out 0x64, al
_check2:
         in al,0x64                         ;键盘缓冲区状态
         and al, 0x02
         jne _check2		 
		 
         mov al, 0x47
         out 0x60, al		 

         ret

;-------------------------------------------------------------------------------
enable_mouse:                               ;启动鼠标
_check3:
         in al,0x64                         ;键盘缓冲区状态
         and al, 0x02
         jne _check3
		 
         mov al, 0xd4
         out 0x64, al
_check4:
         in al,0x64                         ;键盘缓冲区状态
         and al, 0x02
         jne _check4		 
		 
         mov al, 0xf4
         out 0x60, al
		 
         ret
	 
;-------------------------------------------------------------------------------
move_mouse:                                 ;从鼠标数据缓冲区获取数据,并在屏幕上移动鼠标
         
		 pushad

         cli                                ;关中断

_check_loop:
		 
         ;判断缓冲区是否有数据
         mov eax, [mouse_buf_wpnt]          ;获取写指针
         mov ebx, [mouse_buf_rpnt]          ;获取读指针
         cmp eax, ebx                       ;读、写指针比较
         jz _check_finished                 ;如果读、写指针相同,退出 		 
		 
         ;从缓冲区获取一个字符
         xor cx, cx                         ;cx清零
         mov cl, [mouse_buf_addr + ebx]     ;从读指针处获取一个字符
         inc ebx                            ;读指针后移
         cmp ebx, mouse_buf_end             ;读指针是否已经到缓冲区末尾
         jb _rpnt_wrt                       ;未到末尾,直接回写新的读指针值
         xor ebx, ebx                       ;读指针已经到了缓冲区末尾,清零                     
_rpnt_wrt:
         mov [mouse_buf_rpnt], ebx          ;保存新的读指针		 

         ;根据解析状态来处理字符
         mov eax, [mouse_chk_state]         ;当前处理状态
         cmp eax, 1                         ;是否是状态1
         jz _handle_x                       ;处理x的值
         cmp eax, 2                         ;是否是状态2
         jz _handle_y                       ;处理y的值

		 ;处理鼠标命令字 [mouse_chk_state] = 0
_handle_cmd:
         mov byte [mouse_cmd], cl           ;保存命令字
         mov dword [mouse_chk_state], 1     ;状态变为1
         jmp _move_mouse_out         		 

         ;处理x的值 [mouse_chk_state] = 1
_handle_x:
         xor eax, eax
         mov ax, [mouse_x_pnt]              ;获取原鼠标x轴的值
         mov [mouse_x_old_pnt], ax          ;保存原x轴的值
         cmp cl, 0x80                       ;x的值是否大于0x80。如果x的值大于0x80,鼠标向左移动
         jb _x_mov_right
         not cl                             ;取反加一
         inc cl
         cmp cx, ax                         ;要判断x轴是否移动到了屏幕最左端
         jb _x_left_ok                      ;如果移动值小于原x轴的值
         mov cx, ax                         ;鼠标已经移到屏幕最左侧了,调整减数,使鼠标停留在屏幕最左侧
_x_left_ok:		 
         sub ax, cx                         ;原x轴的值减去鼠标左移的值,得到新的x轴的值
		 jmp _x_check_ok                    ;鼠标左移处理完毕,保存新值,并改变命令字状态
		 
_x_mov_right:                               ;鼠标右移
         add ax, cx                         ;原鼠标x轴的值加上右移步数
         cmp ax, 320                        ;是否已经超过屏幕右侧
         jb _x_check_ok                     ;未超过,直接保存x轴的值即可
         mov ax, 319                        ;否则,让x的值保持在320		 
_x_check_ok:		 
		 mov [mouse_x_pnt], ax              ;将新的x轴的值写入内存
         mov dword [mouse_chk_state], 2
         jmp _move_mouse_out
		 
         ;处理y的值 [mouse_chk_state] = 2
_handle_y:
         xor eax, eax
         mov ax, [mouse_y_pnt]              ;获取原鼠标y轴的值
         mov [mouse_y_old_pnt], ax          ;保存原y轴的值
         cmp cl, 0x80                       ;y的值是否大于0x80。如果y的值大于0x80,鼠标向下移动
         jb _y_mov_up
		 not cl
		 inc cl
         add ax, cx                         ;要判断y轴是否移动到了屏幕最下端
         cmp ax, 199
         jb _y_down_ok                      ;如果移动值小于原y轴的值
         mov ax, 199                        ;鼠标已经移到屏幕最上端了,调整减数,使鼠标停留在屏幕最上侧
_y_down_ok:		 
		 jmp _y_check_ok                    ;鼠标上移处理完毕,保存新值,并改变命令字状态
		 
_y_mov_up:                                  ;鼠标上移
         cmp ax, cx                         ;原鼠标y轴的值加上下移步数
         jae _y_up_ok                       ;是否已经超过屏幕最下端了
         mov cx, ax
_y_up_ok:	
         sub ax, cx                         ;否则,让的值保持在199		 
_y_check_ok:		 
		 mov [mouse_y_pnt], ax              ;将新的y轴的值写入内存
         mov dword [mouse_chk_state], 0		 
         
         ;覆盖旧的坐标点
         xor eax, eax		 
         mov bx, [mouse_y_old_pnt]
         mov ax, 320
		 mul bx
         xor ebx, ebx
         mov bx, [mouse_x_old_pnt]
		 mov cl, [mouse_old_point]
         mov byte [pic_mem_addr + eax + ebx], cl

         ;按照新的坐标绘图		
         xor eax, eax		 
		 mov bx, [mouse_y_pnt]
         mov ax, 320                        ;y轴做乘法(y×320) 
		 mul bx
         xor ebx, ebx
         mov bx, [mouse_x_pnt]
         mov cl, [pic_mem_addr + eax + ebx] ;记录被覆盖点的颜色
         mov [mouse_old_point], cl
         mov byte [pic_mem_addr + eax + ebx], 0x1 ;被覆盖点用红色填写
		 
         ;判断是否点击了鼠标左键
         cmp byte [mouse_cmd], 0x09
         jnz _move_mouse_out                ;如果没有点击鼠标,继续判断后续
		 cmp word [mouse_y_pnt], 100        ;如果没有点击在屏幕的下半部分,退出
		 jb _move_mouse_out
         cmp word [mouse_x_pnt], 160
         jb _click_other_app                ;x轴小于160,对应APP1,否则是APP0
         mov byte [USR1_PROC + proc_ctrl.cmd], 0x55 ;APP0被点击了
         jmp _move_mouse_out 		 
_click_other_app:
         mov byte [USR2_PROC + proc_ctrl.cmd], 0x55 ;APP1被点击了
_move_mouse_out:        
         jmp _check_loop                    ;在缓冲区中数据处理完毕之前,死循环

_check_finished:
         sti                                ;开中断
		 
         popad		 
         
         ret

;-------------------------------------------------------------------------------
move_point:                                  ;在屏幕的最上方显示一个连续的亮点
     
	 push eax
     push ecx

	 xor eax, eax
     xor ecx, ecx
     mov ax, [_sys_ponit_x]
     mov cl, [_sys_color]
     mov [pic_mem_addr + eax], cl     
     inc ax
     cmp ax, 320
     jb _wrt_bck_x
	 mov ax, 0
     inc cl
	 cmp cl, 16
     jb _wrt_bck_clr
     mov cl, 1
_wrt_bck_clr:
     mov [_sys_color], cl     	 
_wrt_bck_x:	 
     mov [_sys_ponit_x], ax	 
	 
     pop ecx
     pop eax
     ret		 
	 
;-------------------------------------------------------------------------------
Set_color_palette:                           ;设置前16个调色板的值 
										     ;返回:无
                          
         cli                                 ;关中断
	
         pushad                              ;保存寄存器
	
         xor eax, eax
	
         mov dx, 0x3c8 
         out dx, al                          ;起始调色板号(我从从0开始设置)
	
         mov ecx, 48                         ;一共要写入48个字节,三个对应一个调色板
         xor ebx, ebx
         mov dx, 0x3c9

_color_palette_loop:                         ;依次将每个调色板的R、B、G写入
         mov al, byte [palette_color_buf + ebx]
         shr al, 2
         out dx, al
         inc ebx
         loop _color_palette_loop 	

         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
	 pidt             dw 0
					  dd 0
	 pgdt             dw 0
					  dd gdt_base_address     ;GDT的性地址
					  											 		  
align 4	 
	 sys_click        dd 0                    ;时钟click
     _task_now        dd 0                    ;当前工作进程控制结构地址
     _task_next       dd 0                    ;当前工作进程的下一个结构
     _task_pend_que   dd 0x0                  ;暂停进程队列头
     _task_stop_que   dd 0x0                  ;停止进程队列头
     _task_old        dd 0                    ;保存上一个进程的控制结构地址	 
	 
     _sys_ponit_x     dw 0                    ;亮点在X轴的值
     _sys_color       db 1,0                  ;亮点的颜色	 

align 4	 
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  
     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
     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
     iend
	 
;-------------------------------------------------------------------------------
	 ;设备一共2M内存,其中前1M为系统内存,系统内存可从132K到640K进行分配
     sys_mem_addr     dd  0xc0022000          ;系统可分内存线性地址
     sys_mem_end      equ 0xc00a0000          ;系统可分内存线性地址末尾

	 ;设备一共2M内存,后1M-2M为用户可用内存
     usr_page_addr    dd  0x00100000          ;用户可分页内存硬件地址
     usr_page_end     equ 0x04000000          ;用户可分页内存硬件地址末尾         
	 
	 ;远程调用的地址
	 far_caller_1     dd 0x0                   ;偏移(不用) 
					  dw 0x0                   ;选择子 
	 far_caller_2     dd 0x0                   ;偏移(不用) 
					  dw 0x0                   ;选择子
	 far_caller_3     dd 0x0                   ;偏移(不用) 
					  dw 0x0                   ;选择子				  
	 far_caller_4     dd 0x0                   ;偏移(不用) 
					  dw 0x0                   ;选择子	
					  
     ;下列变量用于鼠标控制
     mouse_cmd        db 0                     ;鼠标命令字
     mouse_old_point  db 0
     filling          db 0,0		 
         
     mouse_x_pnt      dw 160                   ;鼠标当前在屏幕上的x值
     mouse_y_pnt      dw 100                   ;鼠标当前在屏幕上的y值
     mouse_x_old_pnt  dw 160                   ;鼠标在原屏幕上的x值
     mouse_y_old_pnt  dw 100                   ;鼠标在原屏幕上的y值
		 
     mouse_enabled    dd 0x0                   ;鼠标是否初始化成功
     mouse_buf_wpnt   dd 0x0                   ;鼠标数据写指针
     mouse_buf_rpnt   dd 0x0                   ;鼠标数据读指针
     mouse_chk_state  dd 0x0                   ;处理数据数据时的状态标志						  
					  
	 ;调色板的颜色配置数据,共16色
     palette_color_buf    db  0x00, 0x00, 0x00,  ;黑
	                      db  0xff, 0x00, 0x00,  ;亮红
                          db  0x00, 0xff, 0x00,  ;亮绿
                          db  0xff, 0xff, 0x00,  ;亮黄
                          db  0x00, 0x00, 0xff,  ;亮蓝
                          db  0xff, 0x00, 0xff,  ;亮紫
                          db  0x00, 0xff, 0xff,  ;浅亮蓝
                          db  0xff, 0xff, 0xff,  ;白
                          db  0xc6, 0xc6, 0xc6,  ;亮灰
                          db  0x84, 0x00, 0x00,  ;暗红
                          db  0x00, 0x84, 0x00,  ;暗绿
                          db  0x84, 0x84, 0x00,  ;暗黄
                          db  0x00, 0x00, 0x84,  ;暗青
                          db  0x84, 0x00, 0x84,  ;暗紫
                          db  0x00, 0x84, 0x84,  ;浅暗蓝
                          db  0x84, 0x84, 0x84   ;暗灰	  					  
					  
;-------------------------------------------------------------------------------
SECTION core_trail
;-------------------------------------------------------------------------------
core_end:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值