📄 entry.asm
字号:
; entry.asm :
; 内核入口代码, 32位ELF, Protected Mode
;
; Copyright(c) 2007, Alex P.Wonder
; phoenixwonder@gmail.com
;
%include "pm.inc"
SelectorCode32 equ 0x0008
[SECTION .idt]
LABEL_IDT: ;中断描述符表
%rep 32
Gate SelectorCode32, SpuriousHandler, DA_386IGate
%endrep
.020h:
Gate SelectorCode32, SpuriousHandler, DA_386IGate
%rep 95
Gate SelectorCode32, SpuriousHandler, DA_386IGate
%endrep
.080h:
Gate SelectorCode32, MyIntHandler, DA_386IGate
IdtLen equ $ - LABEL_IDT
IdtPtr dw IdtLen ;段界限
dd 0 ;段基址
; End of [SECTION .idt]
[SECTION .text]
extern main
;extern myprint
;
; 系统内核入口:
; 在此之前,中断是被屏蔽掉的(从进入保护模式那一刻开始). 因此,
; 系统入口首先需要做的就是建立在保护模式下的完整的中断机制, 并为
; 多任务管理设置一个定时时钟, 作为任务切换的标准.
;
global _start
_start:
mov ah, 0x0f
mov al, 'V'
mov [gs:((80*11+0)*2)], ax
; --重建保护模式下的中断机制--
xor eax, eax
mov eax, LABEL_IDT
mov dword[IdtPtr + 2], eax
cli
lidt [IdtPtr] ;加载IDTR
call Init8259A ;初始化8259芯片
; mov ax, 0x36 ;C0, MODE3, BIN
; out 0x43, ax
; mov ax, 9c
; out 0x40, al
; mov ax, 2e
; out 0x40, al
; 现在可以开中断了:-)
sti
; 内核系统循环开始
jmp main
;call myprint
;jmp $
;=========================================================
; 子调用函数
;=========================================================
global enable_8259_irq ;允许8259外部中断
enable_8259_irq:
cli
call Init8259A
sti
ret
Init8259A:
mov al, 011h ;ICW1, 主片8259a
out 020h, al
call io_delay
out 0a0h, al ;ICW1, 从片8259a
call io_delay
mov al, 020h ;ICW2,主片, IRQ0对应中断向量0x20, ..IRQ7->0x27
out 021h, al
call io_delay
mov al, 028h ;ICW2,从片,IRQ8对应中断向量0x28, ..IRQ15->0x2f
out 0a1h, al
call io_delay
mov al, 004h ;ICW3,主片,IRQ2对应从8259
out 021h, al
call io_delay
mov al, 002h ;ICW3,从片,对应主片的IRQ2
out 0a1h, al
call io_delay
mov al, 001h ;ICW4,主片,x86模式
out 021h, al
call io_delay
out 0a1h, al ;ICW4,从片,x86模式
call io_delay
mov al, 1111000b ; 屏蔽主8259所有中断, 除定时器中断和键盘中断
mov al, 0x00
out 021h, al ;主片OCW1
call io_delay
mov al, 11101111b ;屏蔽从8259所有中断, 除PS/2鼠标(IRQ12)
out 0a1h, al ;从片OCW1
call io_delay
ret
io_delay:
nop
nop
nop
nop
ret
;==================================================================
; C格 式: void os_setvect(int vectno, void (*isr)(void))
; 说 明:
;
; 参 数:
; vectno -- 中断ID号
; isr -- 欲设置的中断服务程序地址
; 返回值:
;
;==================================================================
global os_setvect
os_setvect:
push ebp
mov ebp, esp
push eax
push ebx
pushfd
cli ;关中断, 开始设置
mov ebx, LABEL_IDT ;取IDT表基址
xor eax, eax
mov eax, [ebp + 8] ;vectno
shl eax, 3 ; vectno*8是第vectno号中断描述符在IDT中的偏移位置
add ebx, eax ; 第vectno号中断描述符在段内的偏移位置
; 此时, ebx已经指向vectno对应中断的中断描述符了.
; 下面就可以开始更改此描述符中的内容,即更改中断处理程序。
; [中断/陷阱门结构]:
; %1 - Selector(中断程序所在的段选择子)
; %2 - HandlerAddr (驱动程序在段内的地址)
; %3 - Attribute (中断属性)
;
; dw %2 & 0ffffh ; 0..15
; dw %1
; dw (%3 & 0ff00h)
; dw (%2 >> 16) & 0ffffh ; 16..31
mov eax, dword [ebp + 12] ;isr
mov word [ebx], ax ; dw %2 & 0ffffh ; 0..15
shr eax, 16 ; dw (%2 >> 16) & 0ffffh ; 16..31
mov word [ebx + 6], ax
mov ax, cs ; 当前代码段作为selector
mov word [ebx + 2], ax
mov ax, 0x8e00 ; DA_386IGate
mov word [ebx + 4], ax
popfd ;恢复原来的中断处理状态
pop ebx
pop eax
leave
ret
;==================================================================
; C格 式: void *os_getvect(int vectno)
; 说 明:
;
; 参 数:
; vectno -- 中断ID号
; 返回值:
;
;==================================================================
global os_getvect
os_getvect:
push ebp
mov ebp, esp
push ebx
push ecx
mov ebx, LABEL_IDT ;取IDT表基址
xor eax, eax
mov eax, [ebp + 8] ;vectno
shl eax, 3 ; vectno*8是第vectno号中断描述符在IDT中的偏移位置
add ebx, eax ; 第vectno号中断描述符在段内的偏移位置
; 此时, ebx已经指向vectno对应中断的中断描述符了.
; 下面就可以开始更改此描述符中的内容,即更改中断处理程序。
; [中断/陷阱门结构]:
; %1 - Selector(中断程序所在的段选择子)
; %2 - HandlerAddr (驱动程序在段内的地址)
; %3 - Attribute (中断属性)
;
; dw %2 & 0ffffh ; 0..15
; dw %1
; dw (%3 & 0ff00h)
; dw (%2 >> 16) & 0ffffh ; 16..31
xor eax, eax
xor ecx, ecx
mov ax, word [ebx] ; 获得处理程序地址的低16位
mov cx, word [ebx + 6] ; 获得处理程序地址的高16位
shl ecx, 16
or eax, ecx
pop ecx
pop ebx
leave
ret
;
; <<中断处理程序>>
;
; 默认中断处理
_SpuriousHandler:
SpuriousHandler equ _SpuriousHandler - $$ + 0x30400
; mov ah, 0ch
; mov al, '!'
; mov [gs:(80*0 + 75)*2], ax ;第0行, 75列
iretd
; 时钟中断处理(8259A), freq=100Hz
_TimeClockHandler:
TimeClockHandler equ _TimeClockHandler - $$ + 0x30400
inc byte [gs:(80*0 + 70)*2]
mov al, 20h
out 20h, al ;发送EOI给主8259片(因为时钟中断是主片产生的,IRQ0).
iretd
; 内核调度处理
_MyIntHandler:
MyIntHandler equ _MyIntHandler - $$ + 0x30400
mov ah, 0ch
mov al, '@'
mov [gs:(80*0 + 20)*2], ax ;第0行, 75列
iretd
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -