中断处理与特权级转移
在上节中出现可能出现的问题-8259A在中断特殊完全嵌套方式下(执行中断服务程序期间,可响应本级中断,在时钟中断会出现问题)同一个引脚的新中断是否可以打断旧中断的处理?
可以从ICW4的设置中(从之前的介绍中得知ICW4的第四位为1时时完全嵌套的方式),但是在时钟中断时没有进行响应本级中断。
问题展示
假设:时钟中断请求周期为5MS,对应的中断服务程序执行时间为10MS,那么,中断服务程序是否会被新的时钟中断请求打断?从ICW4的设置来说,这个新的时钟中断会被响应,但是在实际的运行中没有进行响应。
关于中断优先级
1.中断优先级由8259A管理-高优先级中断请求优先送往处理器
2.处理器决定是否响应中断请求-处理器没有中断优先级的概念
3.在默认情况下-中断服务程序执行时,屏蔽外部中断请求(IF==0),中断服务程序返回后,重新响应外部中断(IF==1)
验证--在对call EnableTimer处设置断对寄存器进行查看,然后对进入程序TimerHandlerFunc后进行断点设置,对IF寄存器进行查看
当代操作系统的设计-两种形态用户态与内核态
1.应用程序(DPL3)执行系统调用时会陷入内核状态(DPL0)-3特权级到0特权级
2.自定义软中断用于系统调用(int 0x80)(从用户态到内核态)
3.通过软中断陷入内核一最高特权级(DPL0)执行系统调用
4.中断服务程序运行与内核态(DPL0)
中断特权级转移过程(三个步骤)
1.处理器通过中断向量找到对应的中断描述符
2.特权级检查-软中断(目标代码DPL<=CPL)[低特权级到高特权级]&&(CPL<=中断描述符);外部中断:CPL>=目标代码段DPL
3.加载目标代码段选择子到cs,加载偏移地址到ip
上图为用户态代码段的压栈实现过程-寄存器变化
中断服务程序返回
1.iret使得处理器从内核态返回用户态
2.返回时进行特权级检查-CPL<=目标代码DPL(高特权级>底特权级),对相关段寄存器轻质清零(指向高特权级数据的段寄存器)
上图为中断结束时的栈恢复
eflags标志寄存器
eflags寄存器
1.IF-系统标志位,决定是否响应外部中断(IF==0,响应外部中断,IF==0,屏蔽外部中断)
2.IOPL-系统标志位,决定是否允许进行IO操作;CPL<=IOPL才能允许IO端口,当且仅当CPL==0时才能改变IOPL的值
3.设置IOPL的方法
在代码中进行设置并查看
从上图可知进行设置之后,IOPL设置为3(在之前中为0)
目标实验-使用软中断实现系统调用
1.定义32位核心代码段(中断函数,系统函数)
2.定义32位任务代码段和数据段(用户程序)
3.通过软中断转移到内核态调用系统函数-低到高
4.在任务代码段使用软中断实现函数功能
.该实验需要注意的是
1.将IOPL设置位3使得用户态和内核态均可访问IO端口
2.特权级转移时会发生栈的变化(定义TSS结构,定义不同栈段)
3.在用户态通过sti指令使得粗略去响应外部中断(必须用户态)
首先需要定义一个32位的内核代码段,需要将一些代码放置后面执行,实现屏幕打印与时钟中断函数,不同的函数有功能号对应其实现
代码
%include "inc.asm"
org 0x9000
jmp ENTRY_SEGMENT
[section .gdt]
; GDT definition
; 段基址, 段界限, 段属性
GDT_ENTRY : Descriptor 0, 0, 0
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32 + DA_DPL3
VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32 + DA_DPL3
DATA32_DESC : Descriptor 0, Data32SegLen - 1, DA_DRW + DA_32 + DA_DPL3
STACK32U_DESC : Descriptor 0, TopOfStack32U, DA_DRW + DA_32 + DA_DPL3
STACK32K_DESC : Descriptor 0, TopOfStack32K, DA_DRW + DA_32 + DA_DPL0
TSS_DESC : Descriptor 0, TSSLen - 1, DA_386TSS + DA_DPL0
KERNEL32_DESC : Descriptor 0, Kernel32SegLen - 1, DA_C + DA_32 + DA_DPL0
; GDT end
GdtLen equ $ - GDT_ENTRY
GdtPtr:
dw GdtLen - 1
dd 0
; GDT Selector
Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL3
VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL3
Data32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL3
Stack32USelector equ (0x0004 << 3) + SA_TIG + SA_RPL3
Stack32KSelector equ (0x0005 << 3) + SA_TIG + SA_RPL0
TSSSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0
Kernel32Selector equ (0x0007 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
[section .idt]
align 32
[bits 32]
IDT_ENTRY:
; IDT definition
; Selector, Offset, DCount, Attribute
%rep 32
Gate Kernel32Selector, DefaultHandler, 0, DA_386IGate + DA_DPL3
%endrep
Int0x20 : Gate Kernel32Selector, TimerHandler, 0, DA_386IGate + DA_DPL3
%rep 95
Gate Kernel32Selector, DefaultHandler, 0, DA_386IGate + DA_DPL3
%endrep
Int0x80 : Gate Kernel32Selector, Int0x80Handler, 0, DA_386IGate + DA_DPL3
%rep 127
Gate Kernel32Selector, DefaultHandler, 0, DA_386IGate + DA_DPL3
%endrep
IdtLen equ $ - IDT_ENTRY
IdtPtr:
dw IdtLen - 1
dd 0
; end of [section .idt]
TopOfStack16 equ 0x7c00
[section .tss]
[bits 32]
TSS_SEGMENT:
dd 0
dd TopOfStack32K ; 0
dd Stack32KSelector ;
dd 0 ; 1
dd 0 ;
dd 0 ; 2
dd 0 ;
times 4 * 18 dd 0
dw 0
dw $ - TSS_SEGMENT + 2
db 0xFF
TSSLen equ $ - TSS_SEGMENT
[section .dat]
[bits 32]
DATA32_SEGMENT:
DTOS db "D.T.OS!", 0
DTOS_OFFSET equ DTOS - $$
INT_80H db "int 0x80", 0
INT_80H_OFFSET equ INT_80H - $$
Data32SegLen equ $ - DATA32_SEGMENT
[section .s16]
[bits 16]
ENTRY_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, TopOfStack16
; initialize GDT for 32 bits code segment
mov esi, CODE32_SEGMENT
mov edi, CODE32_DESC
call InitDescItem
mov esi, DATA32_SEGMENT
mov edi, DATA32_DESC
call InitDescItem
mov esi, STACK32U_SEGMENT
mov edi, STACK32U_DESC
call InitDescItem
mov esi, STACK32K_SEGMENT
mov edi, STACK32K_DESC
call InitDescItem
mov esi, TSS_SEGMENT
mov edi, TSS_DESC
call InitDescItem
mov esi, KERNEL32_SEGMENT
mov edi, KERNEL32_DESC
call InitDescItem
; initialize GDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, GDT_ENTRY
mov dword [GdtPtr + 2], eax
; initialize IDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, IDT_ENTRY
mov dword [IdtPtr + 2], eax
; 1. load GDT
lgdt [GdtPtr]
; 2. close interrupt
; load IDT
; set IOPL to 3
cli
lidt [IdtPtr]
pushf
pop eax
or eax, 0x3000
push eax
popf
; 3. open A20
in al, 0x92
or al, 00000010b
out 0x92, al
; 4. enter protect mode
mov eax, cr0
or eax, 0x01
mov cr0, eax
; 5. load TSS
mov ax, TSSSelector
ltr ax
; 6. jump to 32 bits code
; jmp dword Code32Selector : 0
push Stack32USelector
push TopOfStack32U
push Code32Selector
push 0
retf
; esi --> code segment label
; edi --> descriptor label
InitDescItem:
push eax
mov eax, 0
mov ax, cs
shl eax, 4
add eax, esi
mov word [edi + 2], ax
shr eax, 16
mov byte [edi + 4], al
mov byte [edi + 7], ah
pop eax
ret
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov ax, VideoSelector
mov gs, ax
mov ax, Stack32USelector
mov ss, ax
mov eax, TopOfStack32U
mov esp, eax
mov ax, Data32Selector
mov ds, ax
mov ebp, DTOS_OFFSET
mov dh, 12
mov dl, 33
call Printf
call InitDevInt
call EnableTimer
jmp $
;
;
InitDevInt:
push ax
mov ax, 0
int 0x80
sti
pop ax
ret
; ds:ebp --> string address
; dx --> dh : row, dl : col
Printf:
push ax
push bx
mov ax, 1
mov bx, 0x0C
int 0x80
pop bx
pop ax
ret
;
;
EnableTimer:
push ax
mov ax, 2
int 0x80
pop ax
ret
Code32SegLen equ $ - CODE32_SEGMENT
[section .knl]
[bits 32]
KERNEL32_SEGMENT:
;
;
DefaultHandlerFunc:
iret
DefaultHandler equ DefaultHandlerFunc - $$
;
;
Int0x80HandlerFunc:
ax0:
cmp ax, 0
jnz ax1
call InitDevIntFunc
iret
ax1:
cmp ax, 1
jnz ax2
call PrintString
iret
ax2:
cmp ax, 2
jnz ax3
call EnableTimerFunc
iret
ax3:
iret
Int0x80Handler equ Int0x80HandlerFunc - $$
;
;
TimerHandlerFunc:
push ax
push dx
mov ax, [gs:((80 * 14 + 36) * 2)]
cmp al, '9'
je throtate
inc al
jmp thshow
throtate:
mov al, '0'
thshow:
mov [gs:((80 * 14 + 36) * 2)], ax
mov dx, MASTER_OCW2_PORT
call WriteEOI
pop dx
pop ax
iret
TimerHandler equ TimerHandlerFunc - $$
;
;
Delay:
%rep 5
nop
%endrep
ret
;
;
Init8259A:
push ax
; master
; ICW1
mov al, 00010001B
out MASTER_ICW1_PORT, al
call Delay
; ICW2
mov al, 0x20
out MASTER_ICW2_PORT, al
call Delay
; ICW3
mov al, 00000100B
out MASTER_ICW3_PORT, al
call Delay
; ICW4
mov al, 00010001B
out MASTER_ICW4_PORT, al
call Delay
; slave
; ICW1
mov al, 00010001B
out SLAVE_ICW1_PORT, al
call Delay
; ICW2
mov al, 0x28
out SLAVE_ICW2_PORT, al
call Delay
; ICW3
mov al, 00000010B
out SLAVE_ICW3_PORT, al
call Delay
; ICW4
mov al, 00000001B
out SLAVE_ICW4_PORT, al
call Delay
pop ax
ret
; al --> IMR register value
; dx --> 8259A port
WriteIMR:
out dx, al
call Delay
ret
; dx --> 8259A
; return:
; ax --> IMR register value
ReadIMR:
in ax, dx
call Delay
ret
;
; dx --> 8259A port
WriteEOI:
push ax
mov al, 0x20
out dx, al
call Delay
pop ax
ret
;
;
EnableTimerFunc:
push ax
push dx
mov ah, 0x0C
mov al, '0'
mov [gs:((80 * 14 + 36) * 2)], ax
mov dx, MASTER_IMR_PORT
call ReadIMR
and ax, 0xFE
call WriteIMR
pop dx
pop ax
ret
;
;
InitDevIntFunc:
push ax
push dx
call Init8259A
mov ax, 0xFF
mov dx, MASTER_IMR_PORT
call WriteIMR
mov ax, 0xFF
mov dx, SLAVE_IMR_PORT
call WriteIMR
pop dx
pop ax
ret
; ds:ebp --> string address
; bx --> attribute
; dx --> dh : row, dl : col
PrintString:
push ebp
push eax
push edi
push cx
push dx
print:
mov cl, [ds:ebp]
cmp cl, 0
je end
mov eax, 80
mul dh
add al, dl
shl eax, 1
mov edi, eax
mov ah, bl
mov al, cl
mov [gs:edi], ax
inc ebp
inc dl
jmp print
end:
pop dx
pop cx
pop edi
pop eax
pop ebp
ret
Kernel32SegLen equ $ - KERNEL32_SEGMENT
[section .gsu]
[bits 32]
STACK32U_SEGMENT:
times 1024 * 4 db 0
Stack32USegLen equ $ - STACK32U_SEGMENT
TopOfStack32U equ Stack32USegLen - 1
[section .gsk]
[bits 32]
STACK32K_SEGMENT:
times 1024 * 4 db 0
Stack32KSegLen equ $ - STACK32K_SEGMENT
TopOfStack32K equ Stack32KSegLen - 1
程序运行结果
小结
1.处理器执行中断服务程序期间不再响应新中断(IF==0)
2.如果需要进行中断嵌套,使用sti设置IF标志位(IF==1)
3.IOPL决定是否允许进行IO操作CPL<=IOPL才能访问IO端口