X86系统中断处理与特权级转移 软中断实现系统调用 用户态程序使用软中断扎内核调用内核态程序

2022/1/29 22:05:04

本文主要是介绍X86系统中断处理与特权级转移 软中断实现系统调用 用户态程序使用软中断扎内核调用内核态程序,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

在这里插入图片描述

不会,中断整体是由 处理器 与 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 ;栈顶


这篇关于X86系统中断处理与特权级转移 软中断实现系统调用 用户态程序使用软中断扎内核调用内核态程序的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程