分页模式任务切换测试
该代码,在分页模式下,有两个ring3级的任务,分别输出WY和LS两个字串。
程序为两个任务建立了3级的代码段和数据堆栈段,建立了IDT段,只设置了一个页表,只映射了4M内存空间。
内核代码被复制到0x2000h处,0x0——0x1FFF被用来存放pdt和第一个pet,进入内核代码前,已经为内核代码建立过临时代码段和数据堆栈段,大小都是4G的大段。
内核代码首先初始化内核代码的TSS描述符,然后设置时钟中断TSS和其TSS描述符,;设置任务1和任务2的任务状态段、任务描述符、LDT段描述符和任务状态表。然后设置任务状态表,任务状态表包含任务是否可用和任务的时间片,其中内核任务不作为调度对象,所以在时钟中断中始终将内核任务的可用标志位置位不可用。接着去设置IDT表,将所有的中段都指向其中一个中断函数,再设置8h时钟中断,这个是bios设置的,其实我们需要将这个修改,因为在保护模式下这应该为一个异常处理中断,但只要保证这个程序里不犯这样的错误就行了。
最后设置pdt和pet,并将pdt的第一个表项u/s位设为1这样,其下的pet的表项才可能被ring3的代码访问,将第三个pet表项u/s射为1,映射到ring3的任务代码页,并将0xb8xxx线性地址映射到0xf0xxx,将0xf0xxx映射到0xb8xxx并将f0项的u/s位设为1,这样任务代码就可以访问显存,显示信息。
在时钟中断代码中,主要是搜索可用的任务,然后修改时钟TSS的link字段,修改相对应的任务状态表,最后转移到可用任务代码里。
目前没有实验的是每一个任务独立4G的空间。
下面是内核代码。
setup.asm
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;Setup.ASM
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;本代码进行初始化工作和加载些中断
- ;中断设为22h
- ;输出字符串 输入:ah = 0 DS:SI字符串,0为结束
- ;读取文件到指定内存区域 输入:ah = 1 DS:SI文件名,ES:DI目录表内存区域,
- ; 输出:DX:BX读入到内存区域
- ; al: 0eh 文件未找到 0fh找到文件
- ;中断设为21h
- ;输出各寄存器的值 输出:AX,CX,DX,BX,SP,BP,SI,DI,FLAG
- ;50h:0000h-------------------------------
- ; 根目录表
- ;50h:1c00h-------------------------------
- ; FAT表
- ;50h:3300h-------------------------------
- ; Kernel代码区域
- bits 16
- org 0
- jmp main
- GDT_DESC
- dw 0x18
- gdtaddr dd 0x0
- GDT:
- NULL:
- dw 0x0,0x0,0x0,0x0
- TempCode:
- dw 0xFFFF
- dw 0x0
- dw 0x9A00
- dw 0x00CF
- TempDate:
- dw 0xFFFF
- dw 0x0
- dw 0x9200
- dw 0x00CF
- main:
- mov ax,cs ;初始化
- mov ss,ax
- mov sp,07bffh
- xor ax,ax
- mov ds,ax
- mov es,ax
- ;-----------------------加载实模式中断
- ;开始加载中断,为了避免段间错误,以后所有代码都有段超越前缀
- ;写入22h中断
- cli
- mov di,22h*4
- mov ax,cs
- mov [ds:di+2],ax ;向中断向量表写入段值
- mov ax,WYOS_int22h_proc
- mov [ds:di],ax ;向中断向量表写入偏移
- ;写入21h中断
- mov di,21h*4
- mov ax,cs
- mov [ds:di+2],ax
- mov ax,WYOS_int21h_proc
- mov [ds:di],ax
- sti
- mov ax,cs
- mov ds,ax
- mov si,WYOSMSG
- mov ah,0
- int 22h
- ;------------------------读取kernel.bin的代码
- ;读取32位kernel代码到1000h:0000
- mov si,WYOSKNL
- mov ax,50h
- mov es,ax
- mov di,0
- mov ah,1
- mov dx,1000h
- mov bx,0
- int 22h
- ;------------------------移动kernel代码到2000h处
- cli
- cld
- mov ax,0x1000
- mov ds,ax
- mov si,0
- mov ax,0x200
- mov es,ax
- mov di,0
- mov cx,0x600
- rep movsd
- ;------------------------设置GDT伪描述符
- mov ax,cs
- mov ds,ax
- mov bx,16
- mul bx
- add ax,GDT
- adc dx,0
- mov word [gdtaddr],ax
- mov word [gdtaddr+2],dx
- ;---------------------------加载GDTR
- mov ax,cs
- mov ds,ax
- lgdt [GDT_DESC]
- ;---------------------------打开A20地址线
- call Empty_8042
- mov al,0xd1
- out 0x64,al
- call Empty_8042
- mov al,0xdf
- out 0x64,al
- call Empty_8042
- ;---------------------------设置cr0,进入保护模式
- mov eax,cr0
- or eax,1
- mov cr0,eax
- ;---------------------------设置段选择子,跳转到内核代码中
- mov ax,0x10
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xffff
- jmp 0x8:2000h
- ; ;读取setup代码到2000h:0000
- ; mov si,WYOSSTP
- ; mov ax,50h
- ; mov es,ax
- ; mov di,0
- ; mov ah,1
- ; mov dx,2000h
- ; mov bx,0
- ; int 22h
- ; jmp 2000h:0000
- ;加载完成,剩下的就是完成中断函数
- jmp $ ;程序结束
- ;----------------------------------21h中断代码区------------------------------
- ;21h中断代码
- WYOS_int21h_proc:
- pusha
- push bx
- push ax
- mov bx,7
- mov ah,0eh
- mov al,0dh
- int 10h
- mov al,0ah
- int 10h ;重新换一行
- ;输出ax
- mov al,'A'
- int 10h
- mov al,'X'
- int 10h
- mov al,'='
- int 10h
- pop ax ;取得ax,先输出ah,再输出al
- push ax ;保存ax
- mov al,ah
- call SHOWALASCII
- pop ax
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出cx
- mov al,'C'
- int 10h
- mov al,'X'
- int 10h
- mov al,'='
- int 10h
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出DX
- mov al,'D'
- int 10h
- mov al,'X'
- int 10h
- mov al,'='
- int 10h
- mov al,dh
- call SHOWALASCII
- mov al,dl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出BX
- mov al,'B'
- int 10h
- mov al,'X'
- int 10h
- mov al,'='
- int 10h
- pop bx ;取得bx
- mov cx,bx
- mov bx,7
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出SP
- mov al,'S'
- int 10h
- mov al,'P'
- int 10h
- mov al,'='
- int 10h
- mov cx,sp
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出BP
- mov al,'B'
- int 10h
- mov al,'P'
- int 10h
- mov al,'='
- int 10h
- mov cx,bp
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出SI
- mov al,'S'
- int 10h
- mov al,'I'
- int 10h
- mov al,'='
- int 10h
- mov cx,si
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出DI
- mov al,'D'
- int 10h
- mov al,'I'
- int 10h
- mov al,'='
- int 10h
- mov cx,di
- mov al,ch
- call SHOWALASCII
- mov al,cl
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- ;输出FLAG寄存器
- mov al,0dh
- int 10h
- mov al,0ah
- int 10h ;重新换一行
- mov al,'F'
- int 10h
- mov al,'L'
- int 10h
- mov al,'A'
- int 10h
- mov al,'G'
- int 10h
- mov al,':'
- int 10h
- call SHOWFLAG
- mov al,0dh
- int 10h
- mov al,0ah
- int 10h
- ;输出gdtr寄存器
- mov al,'G'
- int 10h
- mov al,'D'
- int 10h
- mov al,'T'
- int 10h
- mov al,'R'
- int 10h
- mov al,':'
- int 10h
- sgdt [GDT_DESC]
- mov al,byte [gdtaddr+3]
- call SHOWALASCII
- mov al,byte [gdtaddr+2]
- call SHOWALASCII
- mov al,byte [gdtaddr+1]
- call SHOWALASCII
- mov al,byte [gdtaddr]
- call SHOWALASCII
- mov al,byte [GDT_DESC+1]
- call SHOWALASCII
- mov al,byte [GDT_DESC]
- call SHOWALASCII
- mov ah,0eh
- mov al,'h'
- int 10h
- mov al,20h
- int 10h
- popa
- iret
- ;----------------------------------22h中断代码区------------------------------
- WYOS_int22h_proc:
- push ds
- printstr:
- cmp ah,0
- jnz readfile
- call showmsg
- pop ds
- iret
- readfile:
- cmp ah,1
- jz start
- jmp other
- start:
- push cx
- push bx
- push di ;保存di的基址
- pop bx ;取得di的基址
- push bx ;保存di的基址
- add bx,1c00h;计算根目录表的结尾地址
- searchfile:
- cmp BYTE [es:di],0 ;比较目录项第一个字节,如果为0则是到达目录表项尾
- jnz cmpstr ;不为0,比较文件名
- mov al,0eh ;未找到文件
- pop di
- pop bx
- pop cx
- iret
- cmpstr:
- push ax ;保护环境
- push si
- push di
- mov cx,11
- loopnext:
- mov al,[ds:si] ;比较文件名
- mov ah,[es:di]
- cmp al,ah
- jnz next
- inc di
- inc si
- loop loopnext
- pop di
- pop si
- pop ax
- jmp loadfile
- next:
- pop di
- pop si ;恢复环境
- pop ax
- add di,32
- cmp di,bx ;如果大于等于则没发现文件
- jb searchfile
- mov al,0eh ;未发现文件
- pop di
- pop bx
- pop cx
- pop ds
- iret
- loadfile:
- mov ax,[es:di+1ah] ;获得文件第一个簇号
- pop di
- pop bx
- pop cx
- push ds ;保存ds
- push es
- pop ds ;将簇表内存段传给DS
- push si
- push es
- mov es,dx ;获得目标段基址
- mov si,bx ;或的目标段偏移
- push ax ;保存簇号
- loadfiletomem:
- call ReadCluster
- pop ax ;获得簇号
- add si,200h ;增加缓存空间
- push si ;保存si
- mov si,ax ;获得簇号在fat表中的位置
- shr si,01h ;判断是奇簇还是偶簇
- pushf
- add si,ax
- mov ax,[ds:si+1c00h]
- popf
- jc gethigh
- and ax,0fffh
- jmp iseof
- gethigh:
- push cx
- mov cl,4
- shr ax,cl
- pop cx
- iseof:
- cmp ax,0ff8h
- pop si
- jae loadOK
- push ax
- jmp loadfiletomem
- loadOK:
- pop es
- pop si
- pop ds
- pop ds
- iret
- other:
- pop ds
- iret
- ;==========================================================================
- ;SHOWAL
- ;
- ;
- ;
- ;==========================================================================
- SHOWALASCII:
- push ax
- push ax
- al_showhigh:
- shr al,4
- add al,30h
- cmp al,39h
- jbe al_showlow
- add al,7
- mov ah,0eh
- int 10h
- jmp al_low
- al_showlow:
- mov ah,0eh
- int 10h
- al_low: pop ax
- and al,0fh
- add al,30h
- cmp al,39h
- jbe al_endshow
- add al,7
- mov ah,0eh
- int 10h
- jmp al_back
- al_endshow:
- mov ah,0eh
- int 10h
- al_back: pop ax
- ret
- ;==========================================================================
- ;SHOWFLAG
- ;
- ;
- ;
- ;==========================================================================
- SHOWFLAG:
- PUSH BX
- PUSHF
- POP BX
- PUSHF
- PUSH AX
- push cx
- MOV CX,16
- LAST1:
- MOV AL,'0'
- RCL BX,1
- JNC NEXT1
- MOV AL,'1'
- NEXT1: MOV AH,0EH
- INT 10H
- LOOP LAST1
- MOV AL,'B'
- INT 10H
- POP CX
- POP AX
- POPF
- POP BX
- RET
- ;=============================================================================
- ;SHOWMSG
- ;输出一些字符串
- ;入口: DS:SI指向目标字符
- ;返回: 空
- ;=============================================================================
- showmsg:
- push si
- push ax
- push bx
- cld
- mov ah,0eh
- mov bx,7 ;选用0页面和字符前景色7
- nextchar:
- mov al,[si]
- inc si
- or al,al
- jz ok
- int 10h
- jmp nextchar
- ok:
- pop bx
- pop ax
- pop si
- ret
- ;=============================================================================
- ;ReadCluster
- ;读取指定簇号
- ;入口: AX为簇号,ES:SI为缓冲区起始地址
- ;返回: 无
- ;=============================================================================
- ReadCluster:
- dec ax ;修正簇号,前两个簇号表示的不是数据区域
- dec ax
- add ax,33
- xor dx,dx
- mov cx,1
- ;=============================================================================
- ;ReadSectors
- ;读取指定扇区号,指定数目的连续扇区
- ;入口: AX为逻辑扇区号,从零开始。CX为读取的扇区数。ES:SI为缓冲区起始地址
- ;返回: 无
- ;=============================================================================
- ReadSectors:
- pusha
- push cx
- mov bx,18 ;每磁道的扇区数目,ax % 18 + 1就是物理扇区号,而其商就是含磁头的
- ;磁道号,
- ;因为 扇区号 = 磁道数1*磁头数*扇区数+磁头数1*扇区数+扇区数1-1
- ;那么ax/18的商就是磁道数1*磁头数+磁头数1
- ;其商再除以磁头数商就是磁道数,而余数就是磁头数
- div bx
- inc dx ;得到真实的扇区数
- mov cx,dx ;保存到cx
- xor dx,dx ;将得到商,再次除以磁头数目得到
- push cx
- mov cx,2
- div cx
- pop cx
- ;AX就是磁道数,dx就是磁头数
- mov ch,al ;磁道的低8位
- ror ah,2 ;将ah的低二位放到高二位
- or cl,ah ;高二位放到cl的高二位
- mov dh,dl ;将磁头号送入dh
- mov dl,0 ;驱动器号
- pop ax ;获得读取扇区数目
- mov ah,2
- mov bx,si
- int 13h
- popa
- ret
- ;=============================================================================
- ;Empty_8042
- ;等待键盘控制器闲
- ;入口: 无
- ;返回: 无
- ;=============================================================================
- Empty_8042:
- in al,0x64
- test al,0x2
- jnz Empty_8042
- ret
- ;------------------------数据区域---------------------------------------------
- WYOSMSG db 'Kernel Run',0dh,0ah,0
- WYOSERR db 'File not found',0dh,0ah,0
- WYOSKNL db 'KERNEL BIN',0
- ;WYOSKNL db 'MAIN BIN',0
- times 2048-($-$$) db 0
kernel.asm
- ;定义一些段和描述符中字段的偏移
- ;任务状态段各字段偏移
- tss_link equ 0H
- tss_esp0 equ 4H
- tss_ss0 equ 8H
- tss_esp1 equ 0CH
- tss_ss1 equ 10H
- tss_esp2 equ 14H
- tss_ss2 equ 18H
- tss_cr3 equ 1CH
- tss_eip equ 20H
- tss_eflags equ 24H
- tss_eax equ 28H
- tss_ecx equ 2CH
- tss_edx equ 30H
- tss_ebx equ 34H
- tss_esp equ 38H
- tss_ebp equ 3CH
- tss_esi equ 40H
- tss_edi equ 44H
- tss_es equ 48H
- tss_cs equ 4CH
- tss_ss equ 50H
- tss_ds equ 54H
- tss_fs equ 58H
- tss_gs equ 5CH
- tss_ld equ 60H
- tss_IO equ 66H
- bits 32
- org 2000h
- jmp main
- gdt_desc:
- dw 0x820
- gdtaddr dd gdt
- ;=========================
- gdt:
- NULL:
- dw 0x0,0x0,0x0,0x0
- SystemCode:
- dw 0xFFFF
- dw 0x0
- dw 0x9A00
- dw 0x00CF
- SystemData:
- dw 0xFFFF
- dw 0x0
- dw 0x9200
- dw 0x00CF
- CLKTaskDesc: ;时钟任务描述符表
- dw 0x69
- dw 0x0
- dw 0x8900
- dw 0x0080
- UserSpace:
- user times 0x800 db 0 ;留给用户进程的全局描述符,模式采用类似于linux的设置,
- ;ldt0,tss0,ldt1,tss1如此类推,总共可以支持128个用户任务
- ;========================= ;中断描述符表伪描述符
- idt_desc:
- dw 0x800
- idtaddr dd idt
- ;========================= ;中断描述符表
- idt:
- times 0x800 db 0
- ;=========================
- CLKTask: ;时钟任务状态段
- times 102 db 0
- dw $+2 ;I/O许可位图偏移
- db 0xFF ;I/O许可位图结束字节
- KernelTask: ;内核任务状态段
- times 102 db 0
- dw $+2
- db 0xFF ;I/O许可位图结束字节
- TestTask1: ;Task1的任务状态段
- times 102 db 0
- dw $+2
- db 0xFF
- TestTask2: ;Task2的任务状态段。
- times 102 db 0
- dw $+2
- db 0xFF
- LDT1: ;Task1的局部描述符表
- Task1KnlStack:
- dw 0xFFFF
- dw 0x0
- dw 0x9200
- dw 0x00CF
- Task1CodeSeg:
- dw 0xFFFF
- dw 0x0
- dw 0xFA00
- dw 0x00CF
- Task1DataSeg:
- dw 0xFFFF
- dw 0x0
- dw 0xF200
- dw 0x00CF
- LDT2: ;Task2的局部描述符表
- Task2KnlStack:
- dw 0xFFFF
- dw 0x0
- dw 0x9200
- dw 0x00CF
- Task2CodeSeg:
- dw 0xFFFF
- dw 0x0
- dw 0xFA00
- dw 0x00CF
- Task2DataSeg:
- dw 0xFFFF
- dw 0x0
- dw 0xF200
- dw 0x00CF
- ;===========任务状态表
- task_status equ 0h
- task_cpu_time equ 1h
- task_link equ 2h
- TaskStatusTable:
- Task0:
- db 1
- db 0
- dw 0
- Task1:
- db 1
- db 0
- dw 0
- Task2:
- db 0
- db 0
- dw 0
- ;===============代码开始处
- main:
- mov ax,0x10 ;虽然setup程序已经设置过段寄存器,为了程序的正常运行,还是重新设置下
- mov ds,ax
- xor esi,esi
- xor edi,edi
- mov esp,0xA0000
- xor ebp,ebp
- ;设置内核TSS描述符
- mov esi,UserSpace+8 ;获得内核TSSDESC的地址
- mov eax,KernelTask ;内核TSS的地址->eax
- mov word [esi+2],ax ;设置base addr的低16位
- shr eax,16 ;将高16位送入到ax
- mov byte [esi+4],al ;设置base addr中间8位
- mov byte [esi+7],ah ;设置base addr高8位
- mov word [esi],0x69 ;设置TSS的大小
- mov byte [esi+5],0x89 ;设置描述符的类型和访问权限
- mov byte [esi+6],0x80 ;设置段粒度和其他属性
- ;设置时钟TSS
- mov esi,CLKTask
- mov dword [esi+tss_cr3],0
- mov dword [esi+tss_eip],WYOS_clock_task
- mov dword [esi+tss_eflags],0x202
- mov word [esi+tss_es],0x10
- mov word [esi+tss_cs],0x8
- mov word [esi+tss_ds],0x10
- mov word [esi+tss_fs],0x10
- mov word [esi+tss_gs],0x10
- mov word [esi+tss_ss],0x10
- mov dword [esi+tss_esp],0xa0000
- ;设置时钟任务状态段描述符
- mov eax,CLKTask
- mov word [CLKTaskDesc+2],ax
- shr eax,16
- mov byte [CLKTaskDesc+4],al
- mov byte [CLKTaskDesc+7],ah
- ;设置任务1和任务2的任务状态段、任务描述符、LDT段描述符和任务状态表
- ;Task1 TSS
- mov esi,TestTask1
- mov word [esi+tss_ss0],0x4
- mov dword [esi+tss_esp0],0x80000
- mov dword [esi+tss_cr3],0
- mov word [esi+tss_ldt],0x30
- mov dword [esi+tss_eip],Task1Code
- mov dword [esi+tss_eflags],0x202
- mov word [esi+tss_es],0x17
- mov word [esi+tss_cs],0xf
- mov word [esi+tss_ds],0x17
- mov word [esi+tss_fs],0x17
- mov word [esi+tss_gs],0x17
- mov word [esi+tss_ss],0x17
- mov dword [esi+tss_esp],0x90000
- ;TSS DESC
- mov esi,UserSpace+3*8
- mov eax,TestTask1
- mov word [esi+2],ax
- shr eax,16
- mov byte [esi+4],al
- mov byte [esi+7],ah
- mov word [esi],0x69
- mov byte [esi+5],0x89
- mov byte [esi+6],0x0
- ;LDT DESC
- mov esi,UserSpace+2*8
- mov eax,0x18
- mov word [esi],ax
- mov eax,LDT1
- mov word [esi+2],ax
- shr eax,16
- mov byte [esi+4],al
- mov byte [esi+7],ah
- mov byte [esi+5],0x82
- mov byte [esi+6],0x0
- ;Task2
- ;Task2 TSS
- mov esi,TestTask2
- mov word [esi+tss_ss0],0x4
- mov dword [esi+tss_esp0],0x80000
- mov dword [esi+tss_cr3],0
- mov word [esi+tss_ldt],0x40
- mov dword [esi+tss_eip],Task2Code
- mov dword [esi+tss_eflags],0x202
- mov word [esi+tss_es],0x17
- mov word [esi+tss_cs],0xf
- mov word [esi+tss_ds],0x17
- mov word [esi+tss_fs],0x17
- mov word [esi+tss_gs],0x17
- mov word [esi+tss_ss],0x17
- mov dword [esi+tss_esp],0x90000
- ;TSS DESC
- mov esi,UserSpace+5*8
- mov eax,TestTask2
- mov word [esi+2],ax
- shr eax,16
- mov byte [esi+4],al
- mov byte [esi+7],ah
- mov word [esi],0x69
- mov byte [esi+5],0x89
- mov byte [esi+6],0x0
- ;LDT DESC
- mov esi,UserSpace+4*8
- mov eax,0x18
- mov word [esi],ax
- mov eax,LDT2
- mov word [esi+2],ax
- shr eax,16
- mov byte [esi+4],al
- mov byte [esi+7],ah
- mov byte [esi+5],0x82
- mov byte [esi+6],0x0
- ;TaskStatus
- mov esi,TaskStatusTable
- mov byte [esi+task_status],1
- mov byte [esi+task_cpu_time],0
- mov word [esi+task_link],0x28
- add esi,4
- mov byte [esi+task_status],0
- mov byte [esi+task_cpu_time],5
- mov word [esi+task_link],0x38
- add esi,4
- mov byte [esi+task_status],0
- mov byte [esi+task_cpu_time],5
- mov word [esi+task_link],0x48
- ;设置IDT中的时钟中断任务们描述符,暂定为8H,
- mov esi,idt
- mov ecx,256
- SetIdtItem:
- mov eax,WYOS_default_interrupt
- mov word [esi],ax
- mov word [esi+2],0x8
- mov byte [esi+5],0x8E
- shr ax,16
- mov word [esi+6],ax
- add esi,8
- loop SetIdtItem
- mov esi,idt
- mov word [esi+(8H*8+2)],0x18 ;填写8H中断
- mov byte [esi+(8H*8+5)],0x85
- lgdt [gdt_desc]
- lidt [idt_desc]
- mov ax,0x28
- ltr ax
- jmp clear
- clear: ;跳转一下清除高速缓冲寄存器
- ; sti
- ;setpage: ;设置页目录表和第一个页表,先映射4M内存
- setpdt:
- mov ax,0x10
- mov es,ax
- xor edi,edi
- mov eax,0
- mov ecx,0x400
- rep stosd
- ;设置第一个页目录表项
- xor edi,edi
- mov eax,0x1007
- stosd
- setpet:
- mov edi,0x1000
- mov ecx,0x400
- mov eax,3
- setpetvalue:
- stosd
- add eax,0x1000
- loop setpetvalue
- ;设置显示寄存器的虚拟地址为0xf0xxx而0xb8000则指向物理0xf0xxx这一块区间
- mov edi,0x1000
- mov dword [edi+0x3*4],0x3007
- mov dword [edi+0xb8*4],0xf0003
- mov dword [edi+0xf0*4],0xb8007
- ;设置完成进入保护模式
- mov eax,0
- mov cr3,eax
- mov eax,cr0
- or eax,0x80000000
- mov cr0,eax
- jmp clear_pregetinstruction
- clear_pregetinstruction:
- mov byte [0xf0004],'P'
- mov byte [0xf0006],'A'
- mov byte [0xf0008],'G'
- mov byte [0xf000a],'I'
- mov byte [0xf000c],'N'
- mov byte [0xf000e],'G'
- sti
- die: jmp $
- jmp die
- WYOS_default_interrupt:
- push eax
- pushf
- mov al,[WYOS_interrupt_string]
- mov byte [0xf0002],al
- cmp al,0xFF
- jb save
- reset:
- mov al,0
- save:
- inc al
- mov byte [WYOS_interrupt_string],al
- mov al , 0x20
- out 0x20 , al
- out 0xa0 , al
- popf
- pop eax
- iret
- WYOS_clock_task:
- push eax
- push edx
- push esi
- push edi
- ;获得正在运行的任务的任务门选择子
- mov esi,CLKTask
- mov ax,word [esi+tss_link]
- ;通过任务门选择子获得正在运行的任务TID
- shr ax,3
- sub ax,5
- shr ax,1
- or ax,ax
- jnz CheckCpuTime ;如果不是0号任务则检查当前任务的剩余时间片
- ; ;设置返回任务的TID
- mov eax,0
- CheckCpuTime: ;eax包含指向当前的任务的TID
- mov edx,eax ;将TID保存到edx中
- shl eax,2
- mov esi,TaskStatusTable
- add esi,eax
- mov al,byte [esi+task_cpu_time]
- or al,al
- jnz SetCpuTime ;如果剩余时间片不为0,则继续运行该任务
- ;剩余时间片为0,则寻找一个可用的任务,并将当前任务设为可用
- mov ecx,2
- push esi ;保存当前任务的状态表的指针
- mov esi,TaskStatusTable
- search:
- mov al,byte [esi+task_status]
- or al,al
- jz find
- add esi,4
- loop search
- find:
- mov eax,esi ;先将找到的任务的状态表的指针保存到eax,因为要修改以前的任务为可用
- pop esi
- or edx,edx ;如果是0号任务,则不置为可用
- jz SetTaskStatus
- mov byte [esi+task_status],0
- SetTaskStatus:
- mov esi,eax
- mov byte [esi+task_status],1 ;设找到的可用任务为不可用
- mov byte [esi+task_cpu_time],6 ;设为6这是因为下面的SetCpuTime会自动将任务的时间片去1
- SetReturnTSSSel: ;设置返回的任务门选择子
- mov edi,CLKTask
- mov ax,word [esi+task_link]
- mov word [edi+tss_link],ax
- ;将目标任务设为忙
- mov edx,2
- sub edx,ecx
- shl edx,1
- add edx,5
- shl edx,3
- mov edi,gdt
- add edi,edx
- mov edx,[edi+5]
- or edx,0x2
- mov [edi+5],edx
- SetCpuTime: ;esi中包含可用的任务的状态表指针
- mov al,byte [esi+task_cpu_time]
- dec al
- mov byte [esi+task_cpu_time],al
- CLKTaskEnd:
- pop edi
- pop esi
- pop edx
- pop eax
- mov al , 0x20
- out 0x20 , al
- out 0xa0 , al
- iret
- jmp WYOS_clock_task
- WYOS_clock_task_delay:
- ret
- ;============Task1 Code============
- Task1Code:
- mov esi,dword [WYOS_cursor_position]
- cmp esi,0xf0fff
- jc Task1Show
- mov esi,0xf0000
- Task1Show:
- mov ecx,0xFFFF
- Task1_delay:
- loop Task1_delay
- mov byte [esi],'W'
- inc esi
- inc esi
- mov dword [WYOS_cursor_position],esi
- mov byte [esi],'Y'
- inc esi
- inc esi
- mov dword [WYOS_cursor_position],esi
- jmp Task1Code
- ;============Task2 Code============
- Task2Code:
- mov esi,dword [WYOS_cursor_position]
- cmp esi,0xf0fff
- jc Task2Show
- mov esi,0xf0000
- Task2Show:
- mov ecx,0xFFFF
- Task2_delay:
- loop Task2_delay
- mov byte [esi],'L'
- inc esi
- inc esi
- mov dword [WYOS_cursor_position],esi
- mov byte [esi],'S'
- inc esi
- inc esi
- mov dword [WYOS_cursor_position],esi
- jmp Task2Code
- ;==================
- ;其它数据
- WYOS_font_character db 'Y'
- WYOS_interrupt_string db 0
- WYOS_cursor_position dd 0xf0000