汇编网首页登录博客注册
assembird的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  

[2014-10-08 22:14] 自制OS雏形

图片载入中
学习linux 2.4.0内核的小成果,里面借鉴了很多linux中的数据结构、函数、代码、原理等,并非原创。自己在xp上用vc和masm将内核启动的一小部分实现出来。引导,中断,启动内存管理,页表设置等内容,
都已经完成。当然问题多多,不是要写一个系统,而是学习的记录。如果你是大牛就pass吧。如果你是如我一样的菜鸟,学linux内核不知从哪下手,可以看看。在过程中碰到了很多困难,也解决了很多问题。总体觉得比捧着厚厚的内核书籍看,来的深刻,希望对你有所启发。
这是其中的汇编代码,先睹为快:
全部代码下载链接:http://download.csdn.net/detail/hello_pengzhen/8014331

系统引导代码:
;..\..\Bin\ML.EXE /Zm /c /Fl /Sa bootkerdev.asm
;..\..\Bin\LINK5.EXE bootkerdev.obj
assume cs:code
code segment
start:
        mov ax,offset start
        add ax,07c0h
        mov ds,ax
        mov si,offset hello
        push si
        call putstr

loadkernel:
        
        ;加载内核到0x80000,一个扇区
        mov ax, 8000h ;kernel将要存放的内存的段地址
        push ax
        mov ax,02h ;扇区号
        push ax
        mov ax,09h ;扇区数
        push ax
        call loadfp
        
        mov si,offset loadinfo
        push si
        call putstr
        
        ;加载32位初始化代码到0x90000,一个扇区
        mov ax, 9000h ;kernel将要存放的内存的段地址
        push ax
        mov ax,0bh        ;扇区号
        push ax
        mov ax,040h  ;扇区数
        push ax
        call loadfp
        
        mov si,offset loadinitinfo
        push si
        call putstr
        
        DB      0eah     ;操作码 ,jmp 到8000:0000
   DW      0   ;16位偏移量
   DW      8000h ;段值
s:
        jmp s

;显示一个字符
;输入参数:一个ASCII码
;返回参数:无
bios_putchar PROC FAR
        push bp
        mov bp,sp
        push ax
        mov ax,[bp+6]
        mov bl,BYTE PTR 0
        mov ah,0eh
        int 10h
        pop ax
        pop bp
        ret 2
bios_putchar ENDP

putstr PROC FAR
        push bp
        mov bp,sp
        push si
        mov si,[bp+6]
d_disp:
        TEST [si],0FFh
        je d_exit
        push [si]
        call bios_putchar
        inc si
        jmp d_disp
d_exit:
        pop si
        pop bp
        ret 2
putstr ENDP

;参数1:存放的段基址
;参数2:开始读的扇区号
;参数3:要的读的扇区个数
loadfp PROC FAR
        push bp
        mov bp,sp
        push es
        push ax
        push bx
        push dx
        push cx
        
        mov ax, [bp+0ah] ;要存放的内存的段基址,偏移地址都是0
        mov es, ax ; 传递给ES
        mov bx, 0 ; kernel偏移地址为0
        mov dl, 0 ; 驱动器号为0h,为A驱
        mov dh, 0 ; 磁头号为0
        mov ch, 0 ;磁道号为0
        mov cl, BYTE PTR[bp+8h] ;扇区号
        mov al, BYTE PTR[bp+6h] ; 要读的扇区数
        mov ah, 2 ; 调用读磁盘的中断程序
        int 13h
        
        pop cx
        pop dx
        pop bx
        pop ax
        pop es
        pop bp
        ret 6
loadfp ENDP

hello db 'The Simplest Boot Section',13,10,0
loadinfo db 'I Have Load The Kernel Program To 8000:0000',13,10,0
loadinitinfo db 'I Have Load The 32BIT Init Program To 9000:0000',13,10,0
        db 510-($-start) dup (0)
        db 055h
        db 0aah
code ends
end start

保护模式初始化代码:
;名称:minikernel.asm
;功能:演示实方式和保护方式切换(切换到16位代码段)
;..\..\Bin\ML.EXE /c /I. /Zm /Fl /Sa minikernel.asm
;..\..\Bin\LINK5.EXE minikernel.obj
;系统启动后会把程序加载到8000:0000处
;----------------------------------------------------------------------------
.386P

include myos.inc


;----------------------------------------------------------------------------
GOFF EQU 8000h
CSEG            SEGMENT USE16                 ;16位代码段
                ASSUME  CS:CSEG;,DS:DSEG
org 80000h
                                ;----------------------------------------------------------------------------
Start           PROC
                                ;lidt        VGIDT
                ;lgdt    VGDTR
                ;cli                            ;关中断
                ;EnableA20                      ;打开地址线A20
                                ;empty_8042
                                ;mov al,0D1h
                                ;out 064h,al
                                ;empty_8042
                                ;mov al,0dfh
                                ;out 060,al
                                ;empty_8042
                                
                                ;int 15h 获取物理内存
                                ;es 的基地址是0
                                xor eax,eax
                                mov esi,ALT_MEM_K
                                mov es:[esi],eax
get_mem_e820:
                                xor ebx,ebx
                                mov di,E820_MAP
e820_start:
                                mov eax,00000e820h
                                mov edx,SMAP
                                mov ecx,20
                                ;push ds
                                ;pop es
                                int 015h
                                jc e820_fail
                                .if eax!=SMAP
                                        jmp e820_fail
                                .endif
                                mov esi,E820_MAP_NR
                                mov al,es:[esi]
                                .if al>=E820_MAX
                                        jmp e820_fail
                                .endif
                                mov esi,E820_MAP_NR
                                inc BYTE PTR es:[esi]
                                mov ax,di
                                add ax,20
                                mov di,ax
                                .if ebx!=0
                                        jmp e820_start
                                .endif
e820_fail:                
get_mem_e801:
                                mov ax,0e801h
                                int 015h
                                jc e801_fail
                                
                                and edx,0ffffh
                                shl edx,6
                                mov esi,ALT_MEM_K
                                mov es:[esi],edx
                                and ecx,0ffffh
                                add es:[esi],ecx
e801_fail:
get_mem_88:
                                mov ah,088h
                                int 015h
                                mov esi,EXT_MEM_K
                                mov es:[esi],ax
                        
                        ;jmp $;!!!测试        
                                lidt        VGIDT
                lgdt    VGDTR
                cli                            ;关中断
                EnableA20                      ;打开地址线A20
                ;切换到保护方式
                mov     eax,cr0
                or      eax,1
                mov     cr0,eax
                ;清指令预取队列,并真正进入保护方式
                JUMP16  CODE16_SEL,<OFFSET ENTER_32BIT_PROTECTION>
ENTER_32BIT_PROTECTION:        ;现在开始在保护方式下运行
                                 mov          ax,WORD PTR MINI_DATA_SEL
                                 mov     es,ax
                                 mov     ds,ax
                                 mov     fs,ax
                                 mov     gs,ax
                                 mov     ax,WORD PTR MINI_VIDEO_SEL
                                 mov     es,ax
                                 ;mov          ax,WORD PTR MINI_STACK_SEL
                                 ;mov     ss,ax
                                 ;mov          sp,0FFFFh
                                 JUMP16  MINI_CODE_SEL,930h ;930h 是生成的minikernel.map文件中CSEG32起始位置
Start           ENDP
;----------------------------------------------------------------------------
GDT             LABEL   BYTE                  ;全局描述符表
DUMMY           Desc    <>                    ;空描述符
KERNEL_CODE_DESC Desc   <0ffffh,0h,0h,ATCER+DPL0,GL+D32+0fh,0h> ;32位内核代码
MINI_DATA_DESC  Desc    <0ffffh,0h,0h,ATDW+DPL0, GL+D32+0fh,0h> ;32位的数据段
USER_CODE_DESC        Desc    <0ffffh,0h,0h,ATCER+DPL3, GL+D32+0fh,0h> ;32位用户代码段
USER_DATA_DESC  Desc    <0ffffh,0h,0h,ATDW+DPL3, GL+D32+0fh,0h> ;32位的数据段
CODE16_DESC     Desc    <0ffffh,0h,08h,ATCE,0fh,0h>     ;16位初始化代码段
MINI_CODE_DESC        Desc    <0ffffh,0h,08h,ATCE,D32+0fh,0h> ;32位初始化代码段
MINI_VIDEO_DESC Desc    <0ffffh,8000h,0bh,ATDW+DPL0,GL+D32+0fh,0h>  ;视频输出段
LDT_DESC                Desc         <>
TSS_DESC                Desc         <>
;----------------------------------------------------------------------------
GDTLen          =       $-GDT                 ;全局描述符表长度
VGDTR           PDesc   <GDTLen-1,OFFSET GDT+80000h>           ;伪描述符
;----------------------------------------------------------------------------
CODE16_SEL      =       CODE16_DESC     -GDT              ;代码段选择子
MINI_VIDEO_SEL  =       MINI_VIDEO_DESC -GDT             ;源数据段选择子
MINI_CODE_SEL   =       MINI_CODE_DESC  -GDT                         ;32位初始化代码选择子
MINI_DATA_SEL   =       MINI_DATA_DESC  -GDT
KERNEL_CODE_SEL =       KERNEL_CODE_DESC -GDT
USER_CODE_SEL         =                USER_CODE_DESC -GDT
USER_DATA_SEL   =                USER_DATA_DESC -GDT
LDT_SEL                        =                LDT_DESC -GDT
TSS_SEL                        =                TSS_DESC -GDT

IDT                                LABEL        BYTE        ;中断描述符表
        qword        256 dup(0)
IDTLen                        =                $-IDT
VGIDT                        PDesc        <IDTLen-1,OFFSET IDT+080000h>

CODE16_DESCLen = $ - Start
CSEG            ENDS                           ;代码段定义结束

CSEG32            SEGMENT USE32
                ASSUME  CS:CSEG32
C32_EBGIN PROC
                        BIG_JUMP32 KERNEL_CODE_SEL,090000h
C32_EBGIN ENDP
CSEG32            ENDS
                                END     Start

系统建立,中断处理,进入C程序的代码
;名称:miniint.asm
;功能:32位代码段,初始化作用
;注意:此时已经工作在保护模式下
;..\..\Bin\ML.EXE /c /coff /I. /Fl /Sa miniinit.asm
;..\..\Bin\LINK.EXE /ALIGN:16 /BASE:0xC0090000 /ENTRY:kmain /NOLOGO  /MAP:miniinit.map /SUBSYSTEM:CONSOLE  miniinit.obj
;系统启动后会把程序加载到0x00090000处
;!!!必须链接到0xC0090000处!!!
;过程定义距离修饰符必须是NEAR,NEAR调用不会压入cs段选择符。
;一是由于C代码优化后所有的函数都是NEAR,所以保证C调用汇编的程序不会
;出错。二是由于32位的保护模式代码,只有一种FLAT模式,无所谓距离限制了。

.386p
.model flat,stdcall
option casemap: none
include myos.inc

SEAX equ 018h
SES equ 020h
ORIG_EAX equ 024h
SCS equ 02ch
EFLAGS equ 30h

VM_MASK equ 000020000h

.data

note byte "We open the page system !",0
int_msg byte "Unknown interrupt \n",0
GDT_TABLE_ADDR PDesc <0>
IDT_TABLE_ADDR PDesc <0>
sys_ni_syscall proto NEAR stdcall
sys_call_table dword 256 dup(offset sys_ni_syscall)
.code
align
org 0h
;外部变量声明
EXTERN idt_table:DWORD ;IDT指针
EXTERN gdt_table:DWORD ;GDT指针
;C代码中的过程声明
setup_idt proto NEAR stdcall
start_kernel proto NEAR stdcall
do_divide_error proto NEAR stdcall,:DWORD,:DWORD
 do_debug proto NEAR stdcall,:DWORD,:DWORD
 do_nmi proto NEAR stdcall,:DWORD,:DWORD
 do_int3 proto NEAR stdcall,:DWORD,:DWORD
 do_overflow proto NEAR stdcall,:DWORD,:DWORD
 do_bounds proto NEAR stdcall,:DWORD,:DWORD
 do_invalid_op proto NEAR stdcall,:DWORD,:DWORD
 do_device_not_available proto NEAR stdcall,:DWORD,:DWORD
 do_double_fault proto NEAR stdcall,:DWORD,:DWORD
 do_coprocessor_segment_overrun proto NEAR stdcall,:DWORD,:DWORD
 do_invalid_TSS proto NEAR stdcall,:DWORD,:DWORD
 do_segment_not_present proto NEAR stdcall,:DWORD,:DWORD
 do_stack_segment proto NEAR stdcall,:DWORD,:DWORD
 do_general_protection proto NEAR stdcall,:DWORD,:DWORD
 do_page_fault proto NEAR stdcall,:DWORD,:DWORD
 do_coprocessor_error proto NEAR stdcall,:DWORD,:DWORD
 do_simd_coprocessor_error proto NEAR stdcall,:DWORD,:DWORD
 do_alignment_check proto NEAR stdcall,:DWORD,:DWORD
 do_spurious_interrupt_bug proto NEAR stdcall,:DWORD,:DWORD
 do_machine_check proto NEAR stdcall,:DWORD,:DWORD
do_IRQ proto NEAR stdcall,:PTR PT_REGS

;汇编代码中的过程声明
disp_anyting proto NEAR stdcall,straddr:DWORD
set_gate proto NEAR stdcall,gate_addr:DWORD,gtype:BYTE,dpl:BYTE,faddr:DWORD
inter_get_current proto NEAR stdcall
outb proto NEAR stdcall,value:BYTE,port:WORD
outb_p proto NEAR stdcall,value:BYTE,port:WORD
IRQ0x00_interrupt proto NEAR stdcall
IRQ0x01_interrupt proto NEAR stdcall
IRQ0x02_interrupt proto NEAR stdcall
IRQ0x03_interrupt proto NEAR stdcall
IRQ0x04_interrupt proto NEAR stdcall
IRQ0x05_interrupt proto NEAR stdcall
IRQ0x06_interrupt proto NEAR stdcall
IRQ0x07_interrupt proto NEAR stdcall
IRQ0x08_interrupt proto NEAR stdcall
IRQ0x09_interrupt proto NEAR stdcall
IRQ0x0a_interrupt proto NEAR stdcall
IRQ0x0b_interrupt proto NEAR stdcall
IRQ0x0c_interrupt proto NEAR stdcall
IRQ0x0d_interrupt proto NEAR stdcall
IRQ0x0e_interrupt proto NEAR stdcall
IRQ0x0f_interrupt proto NEAR stdcall

;异常与中断过程声明
divide_error proto NEAR stdcall
debug proto NEAR stdcall
nmi proto NEAR stdcall
int3 proto NEAR stdcall
overflow proto NEAR stdcall
bounds proto NEAR stdcall
invalid_op proto NEAR stdcall
device_not_available proto NEAR stdcall
double_fault proto NEAR stdcall
coprocessor_segment_overrun proto NEAR stdcall
invalid_TSS proto NEAR stdcall
segment_not_present proto NEAR stdcall
stack_segment proto NEAR stdcall
general_protection  proto NEAR stdcall
coprocessor_error proto NEAR stdcall
simd_coprocessor_error proto NEAR stdcall
alignment_check proto NEAR stdcall
spurious_interrupt_bug proto NEAR stdcall
machine_check proto NEAR stdcall
page_fault proto NEAR stdcall
system_call proto NEAR stdcall
;--------------------------------------
kmain PROC NEAR
        
        ;从PD_BASE开始的12K清0
        mov esi,PD_BASE
        xor eax,eax
        .repeat
                mov [esi],eax
                add esi,4
                .until esi==INIT_PG_END
        ;设置页目录项
        mov edi,PD_BASE
        ;0~4M
        mov eax,PG0_BASE+INIT_PG_PE_ATTR
        mov [edi],eax
        mov [edi+4*768],eax
        
        ;4M~8M
        mov eax,PG1_BASE+INIT_PG_PE_ATTR
        mov [edi+4],eax
        mov [edi+4*769],eax
        
        mov edi,PG0_BASE ;从PG0_BASE位置填写页表项目,映射0~8MB空间
        mov eax,INIT_PG_PE_ATTR
        .repeat
                mov [edi],eax
                add eax,01000h
                add edi,4h
                .until edi==INIT_PG_END
        
        mov eax,PD_BASE ;也目录表的位置
        mov cr3,eax        ;设置页表基地址,是物理地址
        mov eax,cr0        ;开启分页
        or  eax,080000000h
        mov cr0,eax
        ;jmp far ptr @f
;@@:
        ;!!!非常重要,可以立即以线性地址的形式运行
        BIG_JUMP32 __KERNEL_CODE,<offset @after_page>
@after_page:
        ;设置堆栈
        mov ax,__KERNEL_DATA
        mov ds,ax
        mov es,ax ;es 要及时更新为与ds相同的值,在C语言中的数据传输等功能都会用到
        mov ss,ax
        mov esp,INIT_TASK_UNION+INIT_STACK_SIZE
        
        
        invoke disp_anyting,addr note
        invoke setup_idt
        
        ;初始化,eflags
        mov eax,0h
        push eax
        popfd
        
        xor eax,eax
        lldt ax
        
        sgdt GDT_TABLE_ADDR
        mov eax,GDT_TABLE_ADDR.Base
        mov gdt_table,eax
        lgdt GDT_TABLE_ADDR
        lidt IDT_TABLE_ADDR
        ;test idt是否设置成功
        ;mov edi,0C8000000h
        ;mov eax,0h
        ;mov [edi],eax
        ;进入C代码内核设置阶段
        invoke start_kernel
@@:jmp @b
        
kmain ENDP

disp_anyting PROC NEAR stdcall,straddr:DWORD
        pushad
        xor edi,edi
        xor ax,ax
        mov ah,9h
        shl ah,4
        or ah,4h
        mov esi,straddr
        mov edi,CONSOLE_BASE
.while BYTE PTR ds:[esi]!=0h
        mov al,BYTE PTR ds:[esi]
        mov WORD PTR es:[edi],ax
        inc si
        add di,2
.endw
        popad
        ret ;这个ret指令是必须的,ml 中要增加/Gz 选项
disp_anyting ENDP

ignore_int PROC NEAR stdcall
        cld
        push eax
        push ecx
        push edx
        push es
        push ds
        mov ax,__KERNEL_DATA
        mov ds,ax
        mov es,ax
        invoke disp_anyting,addr int_msg
        pop ds
        pop es
        pop edx
        pop ecx
        pop eax
        ;pop eax;这里模拟,保护异常,有错误码,需先弹出
        ;hlt
        iretd ;之前是iret        
ignore_int ENDP

set_gate PROC NEAR stdcall,gate_addr:DWORD,gtype:BYTE,dpl:BYTE,faddr:DWORD
        push edx
        push eax
        push edi
        mov eax,gate_addr
        mov edi,eax
        mov edx,faddr
        mov eax,__KERNEL_CODE
        shl eax,16
        mov ax,dx
        mov dl,0
        mov dl,dpl
        shl dx,5
        add dl,gtype
        shl dx,8
        add dx,8000h
        mov [edi],eax
        mov [edi+4],edx
        pop edi
        pop eax
        pop edx
        ret
set_gate ENDP

setup_idt PROC NEAR stdcall
        ;设置中断描述符
        ;edx高16位为过程入口点偏移值高16位
        lea edx,ignore_int
        ;eax高16位为段描述符
        mov eax,__KERNEL_CODE
        shl eax,16
        ;eax低16位为过程入口点偏移值低16位
        mov ax,dx
        ;edx低16位为属性值,高4位:P(1bit)=1,DPL(2bit)=0,e(5bit)=中断门,低4位为0
        mov dx,08e00h
        sidt IDT_TABLE_ADDR
        mov edi,IDT_TABLE_ADDR.Base
        mov idt_table,edi
        mov ecx,0
        .while ecx<256
        ;mov [edi],eax
        ;mov [edi+4],edx
        ;test set_gate
        invoke set_gate,edi,0eh,0h,addr ignore_int
        
        add edi,8
        inc ecx
        .endw
        ret
setup_idt ENDP

page_fault PROC NEAR stdcall
        push do_page_fault
        jmp error_code
page_fault ENDP

error_code:
        push ds
        push eax
        xor eax,eax
        push ebp
        push edi
        push esi
        push edx
        dec eax ;eax=-1
        push ecx
        push ebx
        cld
        mov cx,es
        mov esi,[esp+ORIG_EAX] ;提取错误码
        mov edi,[esp+SES]        ;提取处理函数
        mov [esp+ORIG_EAX],eax ;错误码的位置变成-1
        mov [esp+SES],cx ;处理函数的位置变成es的值
        mov edx,esp ;edx 存放栈顶指针
        push esi ;错误码压栈
        push edx ;寄存器组指针压栈
        mov ax,__KERNEL_DATA
        mov ds,ax
        mov es,dx ;
        GET_CURRENT
        call edi
        jmp ret_from_exception

ret_from_exception:

ret_from_intr:
        GET_CURRENT
        ;判断进入中断时CPU的模式,及特权级
        ;mov eax,[esp+EFLAGS]
        ;mov al,[esp+SCS] ;eflags 与 cs 混合
        ;test eax,VM_MASK OR 3
        ;jne ret_with_reschedule
        jmp restore_all

restore_all:
                RESTORE_ALL_M

common_interrupt:
        SAVE_ALL_M
        ;构造一个CALL指令的调用
        push esp ;do_IRQ 指向pt_regs指针,自己添加
        push ret_from_intr
call_do_IRQ:
        jmp do_IRQ
                
divide_error PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_divide_error
        jmp error_code
divide_error endp

debug PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_debug
        jmp error_code
debug endp

nmi PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_nmi
        RESTORE_ALL_M
        
nmi endp

int3 PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_int3
        jmp error_code
int3 endp

overflow PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_overflow
        jmp error_code
overflow endp

bounds PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_bounds
        jmp error_code
bounds endp

invalid_op PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_invalid_op
        jmp error_code
invalid_op endp

device_not_available PROC NEAR stdcall

device_not_available endp

double_fault PROC NEAR stdcall

double_fault endp

coprocessor_segment_overrun PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_coprocessor_segment_overrun
        jmp error_code
coprocessor_segment_overrun endp

invalid_TSS PROC NEAR stdcall
        push do_invalid_TSS
        jmp error_code
invalid_TSS endp


segment_not_present PROC NEAR stdcall
        push do_segment_not_present
        jmp error_code
segment_not_present endp

stack_segment PROC NEAR stdcall
        push do_stack_segment
        jmp error_code
stack_segment endp

general_protection  PROC NEAR stdcall
        push do_general_protection
        jmp error_code
general_protection endp

coprocessor_error PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_coprocessor_error
        jmp error_code
coprocessor_error endp

simd_coprocessor_error PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_simd_coprocessor_error
        jmp error_code
simd_coprocessor_error endp

alignment_check PROC NEAR stdcall
        push do_alignment_check
        jmp error_code
alignment_check endp

spurious_interrupt_bug PROC NEAR stdcall
        push 0 ;造一个错误码
        push do_spurious_interrupt_bug
        jmp error_code
spurious_interrupt_bug endp

machine_check PROC NEAR stdcall                
        push 0 ;造一个错误码
        push do_machine_check
        jmp error_code
machine_check endp

system_call proc NEAR stdcall
        push eax ;保存eax
        SAVE_ALL_M
        GET_CURRENT
        .if eax < NR_SYSCALLS
        call [sys_call_table+eax*4]
        mov [esp+SEAX],eax
        .elseif
        jmp badsys
        .endif
system_call endp
ret_from_sys_call:
        RESTORE_ALL_M
        
badsys:
        mov eax,-1
        mov [esp+SEAX],eax
        jmp ret_from_sys_call

inter_get_current proc NEAR stdcall
        GET_CURRENT
        mov eax,ebx
        ret 
inter_get_current endp
        
outb proc NEAR stdcall,value:BYTE,port:WORD
        push ax
        push dx
        mov al,value
        mov dx,port
        out dx,al
        pop dx
        pop ax
        ret
outb endp

outb_p proc NEAR stdcall,value:BYTE,port:WORD
        push ax
        push dx
        mov al,value
        mov dx,port
        out dx,al
        jmp @f
@@:
        jmp @f
@@:
        jmp @f
@@:
        jmp @f
@@:
        pop dx
        pop ax
        ret
outb_p endp

IRQ0x00_interrupt proc NEAR stdcall
        push 0-256
        jmp common_interrupt
IRQ0x00_interrupt endp

IRQ0x01_interrupt proc NEAR stdcall
        push 1-256
        jmp common_interrupt
IRQ0x01_interrupt endp

IRQ0x02_interrupt proc NEAR stdcall
        push 2-256
        jmp common_interrupt
IRQ0x02_interrupt endp

IRQ0x03_interrupt proc NEAR stdcall
        push 3-256
        jmp common_interrupt
IRQ0x03_interrupt endp

IRQ0x04_interrupt proc NEAR stdcall
        push 4-256
        jmp common_interrupt
IRQ0x04_interrupt endp

IRQ0x05_interrupt proc NEAR stdcall
        push 5-256
        jmp common_interrupt
IRQ0x05_interrupt endp

IRQ0x06_interrupt proc NEAR stdcall
        push 6-256
        jmp common_interrupt
IRQ0x06_interrupt endp

IRQ0x07_interrupt proc NEAR stdcall
        push 7-256
        jmp common_interrupt
IRQ0x07_interrupt endp

IRQ0x08_interrupt proc NEAR stdcall
        push 8-256
        jmp common_interrupt
IRQ0x08_interrupt endp

IRQ0x09_interrupt proc NEAR stdcall
        push 9-256
        jmp common_interrupt
IRQ0x09_interrupt endp

IRQ0x0a_interrupt proc NEAR stdcall
        push 0ah-256
        jmp common_interrupt
IRQ0x0a_interrupt endp

IRQ0x0b_interrupt proc NEAR stdcall
        push 0bh-256
        jmp common_interrupt
IRQ0x0b_interrupt endp

IRQ0x0c_interrupt proc NEAR stdcall
        push 0ch-256
        jmp common_interrupt
IRQ0x0c_interrupt endp

IRQ0x0d_interrupt proc NEAR stdcall
        push 0dh-256
        jmp common_interrupt
IRQ0x0d_interrupt endp

IRQ0x0e_interrupt proc NEAR stdcall
        push 0eh-256
        jmp common_interrupt
IRQ0x0e_interrupt endp

IRQ0x0f_interrupt proc NEAR stdcall
        push 0fh-256
        jmp common_interrupt
IRQ0x0f_interrupt endp

end kmain
评论次数(0)  |  浏览次数(352)  |  类型(默认类型) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码