不会,中断整体是由 处理器 与 8259A中断控制器 共同管理的,虽然8259A可以不停的将中断请求发送给处理器,但是处理器有屏蔽中断的开关,只要当前中断处理还没有完成,就可以将IF置0 即不接受其他中断请求。
处理器没有中断优先级的概念,它只有响应与不响应的概念,当在执行中断处理时,屏蔽外部中断请求时 不响应8259A发来的中断请求。相反 当中断服务程序完成时,重新开始响应8259A的中断请求。
处理器拿到中断向量之后,就会到中断描述符表中查找对应的中断向量,进而找到一个中断描述符,然后继续特权级检查,最后将目标代码段的选择子加载到 cs寄存器,将中断服务程序的偏移地址加载的 ip寄存器,之后就可以执行 中断服务程序了。
低特权级用户态代码段 执行软中断,此时就会发生特权级转移,转移到高特权级内核态代码段执行,此时 栈就会发生变化,既然特权级要转移到高特权级,那么栈就要使用高特权级的栈,于是相关的寄存器就要入栈,包括ss寄存器(栈基地址) esp寄存器(栈顶指针) 这两个寄存器信息 就是指向了 低特权级的栈,将这些寄存器值 压入高特权级栈中,标志寄存器的值也要入栈(eflags),然后返回地址也要入栈,即 cs寄存器的值 以及ip寄存器的值 也要入栈。至此 就可以取执行中断服务程序了,此时 cs寄存器指向了 内核态代码段, ip寄存器指向了 中断服务程序偏移地址,组合就是中断服务程序的入口地址,然后开始执行中断服务程序,执行到遇到 iret指令后 返回。所以 iret指令执行后 使处理器从内核态 返回到 用户态 ,即从高特权级代码段 切换到 低特权级代码段。
inc.asm
; PIC-8259A Ports
MASTER_ICW1_PORT equ 0x20
MASTER_ICW2_PORT equ 0x21
MASTER_ICW3_PORT equ 0x21
MASTER_ICW4_PORT equ 0x21
MASTER_OCW1_PORT equ 0x21
MASTER_OCW2_PORT equ 0x20
MASTER_OCW3_PORT equ 0x20
SLAVE_ICW1_PORT equ 0xA0
SLAVE_ICW2_PORT equ 0xA1
SLAVE_ICW3_PORT equ 0xA1
SLAVE_ICW4_PORT equ 0xA1
SLAVE_OCW1_PORT equ 0xA1
SLAVE_OCW2_PORT equ 0xA0
SLAVE_OCW3_PORT equ 0xA0
MASTER_EOI_PORT equ 0x20
MASTER_IMR_PORT equ 0x21
MASTER_IRR_PORT equ 0x20
MASTER_ISR_PORT equ 0x20
SLAVE_EOI_PORT equ 0xA0
SLAVE_IMR_PORT equ 0xA1
SLAVE_IRR_PORT equ 0xA0
SLAVE_ISR_PORT equ 0xA0
; Segment Attribute
DA_32 equ 0x4000
DA_LIMIT_4K EQU 0x8000
DA_DR equ 0x90
DA_DRW equ 0x92
DA_DRWA equ 0x93
DA_C equ 0x98
DA_CR equ 0x9A
DA_CCO equ 0x9C
DA_CCOR equ 0x9E
; Segment Privilege
DA_DPL0 equ 0x00 ; DPL = 0
DA_DPL1 equ 0x20 ; DPL = 1
DA_DPL2 equ 0x40 ; DPL = 2
DA_DPL3 equ 0x60 ; DPL = 3
; Special Attribute
DA_LDT equ 0x82
DA_TaskGate equ 0x85 ; 任务门类型值
DA_386TSS equ 0x89 ; 可用 386 任务状态段类型值
DA_386CGate equ 0x8C ; 386 调用门类型值
DA_386IGate equ 0x8E ; 386 中断门类型值
DA_386TGate equ 0x8F ; 386 陷阱门类型值
; Selector Attribute
SA_RPL0 equ 0
SA_RPL1 equ 1
SA_RPL2 equ 2
SA_RPL3 equ 3
SA_TIG equ 0
SA_TIL equ 4
PG_P equ 1 ; 页存在属性位
PG_RWR equ 0 ; R/W 属性位值, 读/执行
PG_RWW equ 2 ; R/W 属性位值, 读/写/执行
PG_USS equ 0 ; U/S 属性位值, 系统级
PG_USU equ 4 ; U/S 属性位值, 用户级
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3 ; 段基址, 段界限, 段属性
dw %2 & 0xFFFF ; 段界限1
dw %1 & 0xFFFF ; 段基址1
db (%1 >> 16) & 0xFF ; 段基址2
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
db (%1 >> 24) & 0xFF ; 段基址3
%endmacro ; 共 8 字节
; 门
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0xFFFF) ; 偏移地址1
dw %1 ; 选择子
dw (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
dw ((%2 >> 16) & 0xFFFF) ; 偏移地址2
%endmacro
loader.asm
%include "inc.asm"
org 0x9000
jmp ENTRY_SEGMENT
;全局段描述符表
[section .gdt]
; GDT definition
; 段基址, 段界限, 段属性
GDT_ENTRY : Descriptor 0, 0, 0
;用户代码段 段描述符 3特权级 32位可执行代码段 3特权级
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
;特权级3栈段 描述符 3特权级
STACK32U_DESC : Descriptor 0, TopOfStack32U, DA_DRW + DA_32 + DA_DPL3
;特权级0栈段 描述符 0特权级
STACK32K_DESC : Descriptor 0, TopOfStack32K, DA_DRW + DA_32 + DA_DPL0
;TSS任务状态段 段描述符 0特权级
TSS_DESC : Descriptor 0, TSSLen - 1, DA_386TSS + DA_DPL0
;内核代码段 段描述符 0特权级 32位可执行代码段 0特权级
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
;特权级3栈段描述符 选择子
Stack32USelector equ (0x0004 << 3) + SA_TIG + SA_RPL3
;特权级0栈段描述符 选择子
Stack32KSelector equ (0x0005 << 3) + SA_TIG + SA_RPL0
;TSS任务状态段 段描述符选择子
TSSSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0
;内核代码段 段描述符 选择子
Kernel32Selector equ (0x0007 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
;中断描述符表 每一个中断描述符(中断门)特权级都是3 当做蹦床 跳转到 更高特权级代码段 类似于调用门
[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 ;起始位置 暂时为0 后面初始化
; end of [section .idt]
TopOfStack16 equ 0x7c00
;TSS任务状态段 本质上也是一块内存,所以也需要遵循32位保护模式的编程规则,需要定义对应的段描述符+选择子
[section .tss]
[bits 32]
TSS_SEGMENT:
dd 0
dd TopOfStack32K ; 0 特权级对应的栈信息:栈顶指针
dd Stack32KSelector ; 0 特权级对应的栈信息:栈段基指针
dd 0 ; 1 特权级对应的栈信息 暂时为空
dd 0 ;
dd 0 ; 2 特权级对应的栈信息 暂时为空
dd 0 ;
times 4 * 18 dd 0 ; 往下全部定义为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
;初始化用户代码段 段描述符
mov esi, CODE32_SEGMENT
mov edi, CODE32_DESC
call InitDescItem
mov esi, DATA32_SEGMENT
mov edi, DATA32_DESC
call InitDescItem
;初始化 特权级3 栈段 段描述符
mov esi, STACK32U_SEGMENT
mov edi, STACK32U_DESC
call InitDescItem
;初始化 特权级0 栈段 段描述符
mov esi, STACK32K_SEGMENT
mov edi, STACK32K_DESC
call InitDescItem
;初始化TSS段
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
; retf 降特权级
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
;模拟用户态程序 特权级3
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov ax, VideoSelector
mov gs, ax
mov ax, Stack32USelector
mov ss, ax
;用户态 3特权级 栈信息
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
; 0x80中断设计,模拟系统调?
int 0x80
sti ;打开中断屏蔽总开关
pop ax
ret
;打印字符串函数 软中断模拟系统调用
; ds:ebp --> string address
; dx --> dh : row, dl : col
Printf:
push ax
push bx
; 0x80中断设计,模拟系统调用
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
;模拟内核代码段 特权级0 代码段
[section .knl]
[bits 32] ;32位内核代码段
KERNEL32_SEGMENT:
;
;
DefaultHandlerFunc:
iret
DefaultHandler equ DefaultHandlerFunc - $$
;软中断 中断处理函数, 模拟系统调用
;
Int0x80HandlerFunc:
ax0:
cmp ax, 0 ; 外部设备中断初始化
jnz ax1
call InitDevIntFunc
iret
ax1:
cmp ax, 1 ;打印字符串功能
jnz ax2 ;如果不是 跳转到 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
;初始化8259A
;
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
;打开 主8259A 对应引脚中断屏蔽 即打开中断分开关
;
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
;初始化8259A
call Init8259A
;设置8259A 屏蔽主8259A所有外部设备的中断
mov ax, 0xFF
mov dx, MASTER_IMR_PORT
call WriteIMR
;设置8259A 屏蔽从8259A所有外部设备的中断
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 ;内核代码段长度
;特权级3 栈段
[section .gsu]
[bits 32]
STACK32U_SEGMENT:
times 1024 * 4 db 0
Stack32USegLen equ $ - STACK32U_SEGMENT ;栈长
TopOfStack32U equ Stack32USegLen - 1 ;栈顶
;特权级0 栈段
[section .gsk]
[bits 32]
STACK32K_SEGMENT:
times 1024 * 4 db 0
Stack32KSegLen equ $ - STACK32K_SEGMENT ;栈长
TopOfStack32K equ Stack32KSegLen - 1 ;栈顶