为什么在LDT里面中断有问题
目的是实现两个任务tss1和tss2,tss1输出A然后死循环,当四次时钟中断到来后,切换到tss2,tss2输出B后死循环,等待四次时钟中断后切换到tss1。如此循环往复。可是用切换到tss1后,中断总是有问题,但是在跳入tss1之前,用int 0x20实验,中断时没问题的。轻大家帮忙看一下,本程序用nasm编译。tss1和tss2切换的代码_ispTimer还没来得及实验。
程序源代码:
%macro Descriptor 3;基址,界限,属性
DW%2
DW%1
DB%1 >> 16
DW%3 | ((%2 >> 8) & 0xF00)
DB%1 >> 24
%endmacro
%macro Gate 4 ;selector,Offset,MainAttr,DCount
DW%2
DW%1
DB(%4 & 0x1F)
DB%3
DW%2 >> 16
%endmacro
StartSegEQU0x7C00
;----------------------
;起始代码
ORG 0x0000
[BITS 16]
jmp dword 0x7c0:StartLabel;主要目的是加载CS
StartLabel:
mov ax,cs
mov ds,ax
mov es,ax
mov ax,0x6c00
mov ss,ax
mov sp,0xFFF
;从软盘中读取接下来的8个扇区,到0x7c00 + 512后面,并执行之
;做一个任务切换的逻辑,8个扇区应该是足够了
cli
loop1:
;软盘复位
xor ax,ax
int 13h
;读取接下来的个扇区,任务1和任务2的相关数据,
;编译完成后查看文件大小,看一下扇区够不够
mov ax,0x0208
mov cx,0x0002
xor dx,dx
mov bx,512
int 13h
test ah,0xFF
jnz loop1
;初始化各个段
xor ebx,ebx
mov bx,cs
shl ebx, 4
;初始化GdtItemTss1
moveax,TSS1Start
movedi,GdtItemTss1
callinitDescp
; 初始化 GdtItemLdt1
moveax,_Ldt1Start
movedi,GdtItemLdt1
callinitDescp
;初始化GdtItemTss2
moveax,TSS2Start
movedi,GdtItemTss2
callinitDescp
; 初始化 GdtItemLdt2
moveax,_Ldt2Start
movedi,GdtItemLdt2
callinitDescp
; 初始化 GdtItemISP
moveax,_ispStart
movedi,GdtItemISP
callinitDescp
; 初始化 Ldt1ItemCode
moveax,_Ldt1CodeStart
movedi,Ldt1ItemCode
callinitDescp
; 初始化 Ldt1ItemStack0
moveax,_Ldt1Stack0
movedi,Ldt1ItemStack0
callinitDescp
; 初始化 Ldt1ItemStack3
moveax,_Ldt1Stack3
movedi,Ldt1ItemStack3
callinitDescp
; 初始化 Ldt2ItemCode
moveax,_Ldt2CodeStart
movedi,Ldt2ItemCode
callinitDescp
; 初始化 Ldt2ItemStack0
moveax,_Ldt2Stack0
movedi,Ldt2ItemStack0
callinitDescp
; 初始化 Ldt2ItemStack3
moveax,_Ldt2Stack3
movedi,Ldt2ItemStack3
callinitDescp
; 初始化 GdtItemFstPm
moveax,_FstPm
movedi,GdtItemFstPm
callinitDescp
;初始化GdtItemTmpTSS
moveax,_tmpTSSBegin
movedi,GdtItemTmpTSS
callinitDescp
;初始化临时堆栈GdtTmpStack0
moveax,tmpStack0
movedi,GdtTmpStack0
callinitDescp
;初始化全局数据段GdtItemGlobalData
moveax,_GlobalVariable
movedi,GdtItemGlobalData
callinitDescp
;GDT初始化
lgdt [GdtPtr]
;IDT初始化
lidt [IdtPtr]
;切换到保护模式
mov eax,cr0
or ax,1
mov cr0,eax
jmp GSELFSTPM:0
;----------------------
;输入:ebx:段基址,eax,偏移量,ds:edi,描述符开始地址
initDescp:
addeax,ebx
addedi,2
mov[ds:edi],ax
shreax,16
addedi,2
mov[ds:edi],al
addedi,3
mov[ds:edi],ah
ret
;------------------------------------------------
;下面是GDT
GdtStart:
Descriptor 0 , 0 , 0
GdtItemTss1:
Descriptor 0 , ( TSS1LEN - 1 ) , 0x89
GdtItemLdt1:
Descriptor 0 , ( LDT1LEN - 1 ) , 0x82
GdtItemTss2:
Descriptor 0 , ( TSS2LEN - 1 ) , 0x89
GdtItemLdt2:
Descriptor 0 , ( LDT2LEN - 1 ) , 0x82
GdtItemVideo:
Descriptor 0xB8000 , 0xFFFF , 0xF2 | 0x4000
GdtItemISP:
Descriptor 0 , ( ISPLEN -1 ) , 0x98 | 0x4000
GdtItemFstPm:
Descriptor 0 , ( FSTPMLEN -1 ) , 0x98 | 0x4000
GdtItemTmpTSS:
Descriptor 0 , ( TMPTSSLEN - 1 ) , 0x89
GdtTmpStack0:
Descriptor 0 , ( TMPSTACK0TOP -1 ) , 0x92 | 0x4000
GdtItemGlobalData:
Descriptor 0 , ( TMPSTACK0TOP -1 ) , 0xF2 | 0x4000
GSELTSS1EQUGdtItemTss1 - GdtStart
GSELLDT1EQUGdtItemLdt1 - GdtStart
GSELTSS2EQUGdtItemTss2 - GdtStart
GSELLDT2EQUGdtItemLdt2 - GdtStart
GSELVIDEOEQUGdtItemVideo - GdtStart
GSELISPEQUGdtItemISP - GdtStart
GSELFSTPMEQUGdtItemFstPm - GdtStart
GSELTMPTSSEQUGdtItemTmpTSS - GdtStart
GSELTMPSTACK0EQUGdtTmpStack0 - GdtStart
GSELGLOBALDATAEQUGdtItemGlobalData - GdtStart + 3
GdtPtrdw$ - GdtStart -1
dd0x7c00 + GdtStart
;----------------------------
;以下是一些全局变量
_GlobalVariable:
_SwitchIndexDD0;显示切换控制,数值为_Jiffies/4,当其个位数字
_JiffiesDD0
_tmpDD0
_currentTaskdb1
GLOBALVARIABLELEBEQU( $ - _GlobalVariable )
;----------------------------
times 510 - ($-$$) db 0
db 0x55,0xAA
;----------------------------
;以下是任务1的TSS和LDT
[section .TSS1]
[BITS 32]
TSS1Start:
DD0; Back
DDL1SELSTACK0; 0 级堆栈
DDLDT1STACK0TOP-4;
DD0; 1 级堆栈
DD0;
DD0; 2 级堆栈
DD0;
DD0; CR3
DD0; EIP
DD0x3202; EFLAGS
DD0; EAX
DD0; ECX
DD0; EDX
DD0; EBX
DDLDT1STACK3TOP-4; ESP
DD0; EBP
DD0; ESI
DD0; EDI
DD0; ES
DDL1SELCODE; CS
DDL1SELSTACK3; SS
DDGSELGLOBALDATA; DS
DD0; FS
DDGSELVIDEO; GS
DDGSELLDT1; LDT
DW0; 调试陷阱标志
DW$ - TSS1Start + 2; I/O位图基址
DB0ffh; I/O位图结束标志
TSS1LENEQU( $ - $$)
[section .ldt1]
[BITS 32]
_Ldt1Start:
Ldt1ItemCode:
Descriptor 0 , LDT1CODELEN - 1 , 0xf8 | 0x4000
Ldt1ItemStack0:
Descriptor 0 , LDT1STACK0TOP -1 , 0x92 | 0x4000
Ldt1ItemStack3:
Descriptor 0 , LDT1STACK0TOP -1 , 0xf2 | 0x4000
L1SELCODEEQU( Ldt1ItemCode - _Ldt1Start) | 0x7
L1SELSTACK0EQU( Ldt1ItemStack0 - _Ldt1Start) | 0x4
L1SELSTACK3EQU( Ldt1ItemStack3 - _Ldt1Start) | 0x7
LDT1LENEQU( $ - $$)
;-------------------------------
;以下是任务2的TSS和LDT
[section .TSS2]
[BITS 32]
TSS2Start:
DD0; Back
DDL2SELSTACK0; 0 级堆栈
DDLDT2STACK0TOP-4;
DD0; 1 级堆栈
DD0;
DD0; 2 级堆栈
DD0;
DD0; CR3
DD0; EIP
DD0x3202; EFLAGS
DD0; EAX
DD0; ECX
DD0; EDX
DD0; EBX
DDLDT1STACK3TOP-4; ESP
DD0; EBP
DD0; ESI
DD0; EDI
DD0; ES
DDL2SELCODE; CS
DDL1SELSTACK3; SS
DDGSELGLOBALDATA; DS
DD0; FS
DDGSELVIDEO; GS
DDGSELLDT2; LDT
DW0; 调试陷阱标志
DW$ - TSS2Start+ 2; I/O位图基址
DB0ffh; I/O位图结束标志
TSS2LENEQU( $ - $$)
[section .ldt2]
[BITS 32]
_Ldt2Start:
Ldt2ItemCode:
Descriptor 0 , LDT2CODELEN - 1 , 0xf8 | 0x4000
Ldt2ItemStack0:
Descriptor 0 , LDT2STACK0TOP -1 , 0x92 | 0x4000
Ldt2ItemStack3:
Descriptor 0 , LDT2STACK0TOP -1 , 0xF2| 0x4000
L2SELCODEEQU( Ldt2ItemCode - _Ldt2Start) | 0x7
L2SELSTACK0EQU( Ldt2ItemStack0 - _Ldt2Start) | 0x4
L2SELSTACK3EQU( Ldt2ItemStack3 - _Ldt2Start) | 0x7
LDT2LENEQU( $ - $$)
;----------------------------------------------------
;第一次进入保护模式的代码
[section .FstPm]
[BITS 32]
_FstPm:
;ICW1
mov al,0x11
out 0x20,al
out 0xA0,al
;ICW2
mov al,0x20
out 0x21,al
mov al,0x28
out 0xA1,al
; ICW3
mov al,04
out 0x21,al
mov al,2
out 0xA1,al
; ICW4
mov al,1
out 0x21,al
out 0xA1,al
; OCW1; mask all interupt
mov al,0xFF
out 0x21,al
out 0xA1,al
;开启时钟中断
mov AL,0xFE
out 21h,AL
mov AL,0xFF
out 0xA1,AL
mov ax,GSELTMPTSS
ltr ax
mov ax,GSELTMPSTACK0
mov ss,ax
mov esp,TMPSTACK0TOP-4
int 0x19
jmp GSELTSS1:0
jmp $
FSTPMLENEQU( $ - $$ )
[section .tmpTSS]
[BITS 32]
_tmpTSSBegin:
DD0; Back
DDGSELTMPSTACK0; 0 级堆栈
DDTMPSTACK0TOP-4;
DD0; 1 级堆栈
DD0;
DD0; 2 级堆栈
DD0;
DD0; CR3
DD0; EIP
DD0; EFLAGS
DD0; EAX
DD0; ECX
DD0; EDX
DD0; EBX
DD0; ESP
DD0; EBP
DD0; ESI
DD0; EDI
DD0; ES
DD0; CS
DD0; SS
DD0; DS
DD0; FS
DD0; GS
DD0; LDT
DW0; 调试陷阱标志
DW$ - _tmpTSSBegin + 2; I/O位图基址
DB0ffh; I/O位图结束标志
TMPTSSLENEQU( $ - $$)
tmpStack0:
TMPSTACK0TOPEQU256
times TMPSTACK0TOP db 0
times 4 db 0
;-----------------------------------
;以下是中断服务程序每经历4次时间中断,切换任务一次
[section .isp]
[BITS 32]
_ispStart:
nop
nop
iretd
_ispTimer:
mov ax,GSELVIDEO
mov gs,ax
mov edi,2
mov WORD [gs:edi],0xc48
mov edi,4
mov WORD [gs:edi],0xc49
mov al,20h;EOI of 8259A
out 20h,al
jmp $
mov edi,_Jiffies - _GlobalVariable
inc DWORD [edi]
mov eax,[edi]
shr eax,2
and eax,1
add eax,1;此时eax是当前应该的任务
mov esi , _currentTask - _GlobalVariable
mov bl,[esi]
cmp al,bl
jnz chgtask
jmp RetBack
chgtask:
mov [esi],al
shl eax,4
sub eax,8
mov edi , _tmp - _GlobalVariable
mov [edi],eax
jmp [edi]
RetBack:
iretd
ISPLENEQU( $ - $$ )
;---------------------------------------------
;ldt1,显示A然后等待时钟中断切换,死循环,只运行于ring3
[section .ldt1]
[BITS 32]
_Ldt1CodeStart:
int 0x19
.loop1:
mov edi, _SwitchIndex - _GlobalVariable
mov eax , [edi]
test eax,1
jnz .loop1
shl eax,1
mov WORD [gs:eax],0xc41
inc DWORD [edi]
jmp .loop1
LDT1CODELENEQU( $ - $$ )
_Ldt1Stack0:
LDT1STACK0TOPEQU256
timesLDT1STACK0TOP db 0
times4 db 0
_Ldt1Stack3:
LDT1STACK3TOPEQU256
timesLDT1STACK0TOP db 0
times4 db 0
;-----------------------
;ldt2的代码段及数据段
;显示B然后等待任务切换,死循环,,只运行于ring3
;由于ring3没有使用堆栈,ring0使用了堆栈,所以把代码段接下来256字节用于ring0堆栈
[section .ldt2]
[BITS 32]
_Ldt2CodeStart:
int 0x19
.loop2:
mov edi , _SwitchIndex - _GlobalVariable
mov eax , [edi]
test eax,1
jz .loop2
shl eax,1
mov WORD [gs:eax],0xc42
inc DWORD [edi]
jmp .loop2
LDT2CODELENEQU( $ - $$ )
_Ldt2Stack0:
LDT2STACK0TOPEQU256
timesLDT2STACK0TOP db 0
times4 db 0
_Ldt2Stack3:
LDT2STACK3TOPEQU256
timesLDT2STACK0TOP db 0
times4 db 0
;-------------------------------------------
;以下部分idt描述符
[section .idt]
[BITS 32]
IdtStart:
%rep 32
GateGSELISP , 0, 0xEE , 0
%endrep
IdtItemTimer0:GateGSELISP , _ispTimer - _ispStart , 0xEE , 0
IdtPtr:
dw$ - IdtStart -1
dd0x7c00 + IdtStart
[最优解释]
TSS现在的几个主流OS都没使用,没研究过,楼主再细细看看intel开发者手册吧。
[其他解释]
感谢回复哈,我找到原因了,是TSS里面的ESP0和SS0的位置写反了。做这个纯粹是个人在看书的时候写的东西。
现在把调试好的源代码发出来哈:
%macro Descriptor 3;基址,界限,属性
DW%2
DW%1
DB%1 >> 16
DW%3
[其他解释]
((%2 >> 8) & 0xF00)
DB%1 >> 24
%endmacro
%macro Gate 4 ;selector,Offset,MainAttr,DCount
DW%2
DW%1
DB(%4 & 0x1F)
DB%3
DW%2 >> 16
%endmacro
StartSegEQU0x7C00
;----------------------
;起始代码
ORG 0x0000
[BITS 16]
jmp dword 0x7c0:StartLabel;主要目的是加载CS
StartLabel:
mov ax,cs
mov ds,ax
mov es,ax
mov ax,0x6c00
mov ss,ax
mov sp,0xFFF
;从软盘中读取接下来的8个扇区,到0x7c00 + 512后面,并执行之
;做一个任务切换的逻辑,8个扇区应该是足够了
cli
loop1:
;软盘复位
xor ax,ax
int 13h
;读取接下来的个扇区,任务1和任务2的相关数据,
;编译完成后查看文件大小,看一下扇区够不够
mov ax,0x0208
mov cx,0x0002
xor dx,dx
mov bx,512
int 13h
test ah,0xFF
jnz loop1
;初始化各个段
xor ebx,ebx
mov bx,cs
shl ebx, 4
;初始化GdtItemTss1
moveax,TSS1Start
movedi,GdtItemTss1
callinitDescp
; 初始化 GdtItemLdt1
moveax,_Ldt1Start
movedi,GdtItemLdt1
callinitDescp
;初始化GdtItemTss2
moveax,TSS2Start
movedi,GdtItemTss2
callinitDescp
; 初始化 GdtItemLdt2
moveax,_Ldt2Start
movedi,GdtItemLdt2
callinitDescp
; 初始化 GdtItemISP
moveax,_ispStart
movedi,GdtItemISP
callinitDescp
; 初始化 Ldt1ItemCode
moveax,_Ldt1CodeStart
movedi,Ldt1ItemCode
callinitDescp
; 初始化 Ldt1ItemStack0
moveax,_Ldt1Stack0
movedi,Ldt1ItemStack0
callinitDescp
; 初始化 Ldt1ItemStack3
moveax,_Ldt1Stack3
movedi,Ldt1ItemStack3
callinitDescp
; 初始化 Ldt2ItemCode
moveax,_Ldt2CodeStart
movedi,Ldt2ItemCode
callinitDescp
; 初始化 Ldt2ItemStack0
moveax,_Ldt2Stack0
movedi,Ldt2ItemStack0
callinitDescp
; 初始化 Ldt2ItemStack3
moveax,_Ldt2Stack3
movedi,Ldt2ItemStack3
callinitDescp
; 初始化 GdtItemFstPm
moveax,_FstPm
movedi,GdtItemFstPm
callinitDescp
;初始化GdtItemTmpTSS
moveax,_tmpTSSBegin
movedi,GdtItemTmpTSS
callinitDescp
;初始化临时堆栈GdtTmpStack0
moveax,tmpStack0
movedi,GdtTmpStack0
callinitDescp
;初始化全局数据段GdtItemGlobalData
moveax,_GlobalVariable
movedi,GdtItemGlobalData
callinitDescp
;GDT初始化
lgdt [GdtPtr]
;IDT初始化
lidt [IdtPtr]
;切换到保护模式
mov eax,cr0
or ax,1
mov cr0,eax
jmp GSELFSTPM:0
;----------------------
;输入:ebx:段基址,eax,偏移量,ds:edi,描述符开始地址
initDescp:
addeax,ebx
addedi,2
mov[ds:edi],ax
shreax,16
addedi,2
mov[ds:edi],al
addedi,3
mov[ds:edi],ah
ret
;------------------------------------------------
;下面是GDT
GdtStart:
Descriptor 0 , 0 , 0
GdtItemTss1:
Descriptor 0 , ( TSS1LEN - 1 ) , 0x89
GdtItemLdt1:
Descriptor 0 , ( LDT1LEN - 1 ) , 0x82
GdtItemTss2:
Descriptor 0 , ( TSS2LEN - 1 ) , 0x89
GdtItemLdt2:
Descriptor 0 , ( LDT2LEN - 1 ) , 0x82
GdtItemVideo:
Descriptor 0xB8000 , 0xFFFF , 0xF2