参考
https://blog.51cto.com/13475106/category6.html及狄泰软件相关课程
中断处理与特权级转移
在上节中出现可能出现的问题-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端口