卓一笔记---中断表(INT表)的使用

   本节主要讲解如何利用INT表显示一些信息.INT表中文名为中断表,在上节中利用int 15h求出了系统内存的信息,这就是一个中断程序.INT表中存储的是中断向量,我们可以自定义中断和中断向量表,然后利用int 指令显示自己想要的信息.

1.构建pm.inc文件,中断向量显示时需要的一些属性

DA_LDT          EQU 82h;局部描述符表段类型值
DA_32           EQU 4000h ;32位段
DA_LIMIT_4K	EQU	8000h	; 段界限粒度为 4K 字节

DA_DRW		EQU	92h	; 存在的可读写数据段属性值
DA_DRWA		EQU	93h	; 存在的已访问可读写数据段类型值
DA_C            EQU     98h  ;存在的只执行代码段属性
DA_CR		EQU	9Ah	; 存在的可执行可读代码段属性值

DA_DPL0		EQU	  10h	; DPL = 0
DA_DPL1		EQU	  20h	; DPL = 1
DA_DPL2		EQU	  40h	; DPL = 2
DA_DPL3		EQU	  60h	; DPL = 3

DA_386CGate	EQU	  8Ch	; 386 调用门类型值
DA_386IGate	EQU	  8Eh	; 386 中断门类型值

;----------------------------------------------------------------------------
; 分页机制使用的常量说明
;----------------------------------------------------------------------------
PG_P		EQU	1	; 页存在属性位
PG_RWW		EQU	2	; R/W 属性位值, 读/写/执行
PG_USU		EQU	4	; U/S 属性位值, 用户级

SA_RPL0         EQU       0h    ;RPL = 0
SA_RPL1         EQU       1h    ;RPL = 1
SA_RPL2         EQU       2h    ;RPL = 2
SA_RPL3         EQU       3h    ;RPL = 3

SA_TIG		EQU	0	; ┓TI
SA_TIL		EQU	4	; ┛

;GDT描述符定义,传进来的参数会自动装到对应的字节中
;usage:Descriptor Base,Limit,Attr
%macro Descriptor 3
       dw %2&0FFFFh ;段界限1
       dw %1&0FFFFh ;段基址1
       db (%1>>16)&0FFh ;段基址2
       dw ((%2>>8)&0F00h)|(%3&0F0FFh) ;属性1 + 段界限2 + 属性2
       db (%1>>24)&0FFh ;段基址3
%endmacro ;共8个字节

; 门
; usage: Gate Selector, Offset, DCount, Attr
;        Selector:  dw
;        Offset:    dd
;        DCount:    db
;        Attr:      db
%macro Gate 4
	dw	(%2 & 0FFFFh)				; 偏移 1				(2 字节)
	dw	%1					; 选择子				(2 字节)
	dw	(%3 & 1Fh) | ((%4 << 8) & 0FF00h)	; 属性					(2 字节)
	dw	((%2 >> 16) & 0FFFFh)			; 偏移 2				(2 字节)
%endmacro ; 共 8 字节

2.构建pmint.asm文件,主要利用中断在屏幕第一行先显示一个字符"!",然后显示一个字符"I",接着打开可屏蔽中断,利用时钟可屏蔽中断让后一个字符动态变化

%include "pm.inc" ;常量,宏,以及一些说明
org 0100h
jmp LABEL_BEGIN
[SECTION .gdt]
; GDT      段基址,  段界限,   段属性
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
LABEL_DESC_CODE32:   Descriptor 0, SegCode32Len-1, DA_CR+DA_32		; 可读执行代码, 32
LABEL_DESC_STACK:    Descriptor 0,     TopOfStack, DA_DRWA+DA_32 ;32位Stack
LABEL_DESC_VIDEO:    Descriptor 0B8000h,   0ffffh, DA_DRW ;显存首地址
;GDT 结束

GdtLen equ $ - LABEL_GDT ;GDT长度
GdtPtr dw GdtLen - 1 ;GDT界限
       dd 0          ;GDT基地址
; GDT选择子
SelectorCode32		equ	LABEL_DESC_CODE32	- LABEL_GDT
SelectorStack		equ	LABEL_DESC_STACK	- LABEL_GDT
SelectorVideo		equ	LABEL_DESC_VIDEO	- LABEL_GDT
;END of SECTION .gdt      

;IDT
[SECTION .idt]
ALIGN 32
[BITS 32]
LABEL_IDT:
 ;门: 目标段选择子, 偏移,DCount,属性
%rep 32
       Gate SelectorCode32,SupriousHandler, 0, DA_386IGate
%endrep
.020h: Gate SelectorCode32,   ClockHandler, 0, DA_386IGate
%rep 95
       Gate SelectorCode32,SupriousHandler, 0, DA_386IGate
%endrep
.080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGate

IdtLen equ $ - LABEL_IDT
IdtPtr dw  IdtLen - 1  ;段界限
       dd  0           ;idt段基地址
;End of section .idt


;全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
  times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
;END of [SECTION .gs]

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
   mov ax, cs
   mov ds, ax
   mov es, ax
   mov ss, ax
   mov sp,0100h
   

   ; 初始化 32 位代码段描述符
   xor	eax, eax
   mov	ax, cs
   shl	eax, 4
   add	eax, LABEL_SEG_CODE32
   mov	word [LABEL_DESC_CODE32 + 2], ax
   shr	eax, 16
   mov	byte [LABEL_DESC_CODE32 + 4], al
   mov	byte [LABEL_DESC_CODE32 + 7], ah


   ; 初始化堆栈段描述符
   xor	eax, eax
   mov	ax, ds
   shl	eax, 4
   add	eax, LABEL_STACK
   mov	word [LABEL_DESC_STACK + 2], ax
   shr	eax, 16
   mov	byte [LABEL_DESC_STACK + 4], al
   mov	byte [LABEL_DESC_STACK + 7], ah

   ; 为加载 GDTR 作准备
   xor	eax, eax
   mov	ax, ds
   shl	eax, 4
   add	eax, LABEL_GDT		; eax <- gdt 基地址
   mov	dword [GdtPtr + 2], eax	; [GdtPtr + 2] <- gdt 基地址

   ;为加载IDTR做准备
   xor eax,eax
   mov ax, ds
   shl eax,4
   add eax,LABEL_IDT 
   mov dword [IdtPtr + 2], eax;

   ; 加载 GDTR
   lgdt	[GdtPtr]

   ; 关中断
   cli

   ;加载IDTR
   lidt [IdtPtr]
 
   ; 打开地址线A20
   in	al, 92h
   or	al, 00000010b
   out	92h, al

   ; 准备切换到保护模式
   mov	eax, cr0
   or	eax, 1
   mov	cr0, eax

   ; 真正进入保护模式
   jmp	dword SelectorCode32:0	; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处

[SECTION .s32] ;32位代码段,由实模式跳入
[BITS 32]
LABEL_SEG_CODE32:
  mov ax, SelectorVideo
  mov gs, ax

  mov ax, SelectorStack  ;堆栈段选择子
  mov ss, ax
  mov esp, TopOfStack 
 
  call Init8259A
  
  int 021h  ;显示一个"!"
  int 080h  ;显示一个动态的字符
  sti       ;利用时钟中断显示一个动态的字符
  jmp $

;Init8259A------
Init8259A:
   mov al,011h
   out 020h,al   ;主8259,ICW1
   call io_delay 

   out 0A0h,al   ;从8259,ICW1
   call io_delay 
   
   mov  al,020h   ;IRQ0对应中断向量0x20
   out  021h,al   ;主8259,ICW2
   call io_delay 
   
   mov  al,028h   ;IRQ8对应中断向量0x28
   out  0A1h,al   ;从8259,ICW2
   call io_delay 
  
   mov  al,004h   ;IRQ2对应从8259
   out  021h,al   ;从8259,ICW3
   call io_delay 
   
   mov  al,002h   ;对应主8259的IR2
   out  0A1h,al   ;从8259,ICW3
   call io_delay 

   mov  al, 001h
   out  021h,al   ;主8259,ICW4
   call io_delay
   
   out  0A1h,al   ;从8259,ICW4
   call io_delay
   
   mov  al, 11111110b ;仅开启定时器中断
   out  021h, al      ;主8259, OCW1
   call io_delay

   mov  al, 11111111b ;屏蔽从8259所有中断
   out  0A1h,al       ;从8259,OCW1
   call io_delay

   ret
;Init8259A结束---------

io_delay:
   nop
   nop
   nop
   nop
   ret

;int handler
_ClockHandler:
ClockHandler equ _ClockHandler - $$
   inc  byte [gs: (80*0+70)*2] ;屏幕第0行
   mov  al, 20h
   out  20h,al         ;发送EOI
   iretd

_UserIntHandler:
UserIntHandler equ _UserIntHandler - $$
   mov ah,0Ch
   mov al,'I'
   mov [gs:((80*0+70)*2)], ax
   iretd

_SupriousHandler:
SupriousHandler  equ  _SupriousHandler - $$
   mov ah,0ch
   mov al,'!'
   mov [gs:((80*0+75)*2)],ax ;屏幕第0行,第75列
   iretd
;--------
    
SegCode32Len	equ	$ - LABEL_SEG_CODE32
; END of [SECTION .s32]

3.构建MakeFileLDT文件用来编译程序

##################################################
# Makefile of pmtestx.asm (x=[1,2,3...])
##################################################

SRC:=pmint.asm
BIN:=$(subst .asm,.com,$(SRC)) #${SRC}中的.asm会替换成.com
#此句等价于pmprotect2real.com

.PHONY : everything

everything : $(BIN)
	sudo mount -o loop pm.img /mnt/floppy/
	sudo cp $(BIN) /mnt/floppy/ -fv
	sudo umount /mnt/floppy/

$(BIN) : $(SRC)
	nasm $< -o $@ 

4.执行make -f MakeFileLDT编译程序,调用命令bochs -f bochsrcdos执行程序得到下面的效果

源码地址:https://github.com/Foolegend/aos/tree/master/chapter03/INT

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值