addinter.asm
[BITS 32]
[GLOBAL _addin] ;我们必须导出这个函数让C程序使用,注意此函数名不用出现在头文件里
[EXTERN _keyboard_interrupt_handle] ;用到本文件外定义的函数
[SECTION .data]
pdescr equ 0x8000
null equ 0h
os_code32_sel equ 8h ;1,gdt,rpl=00
os_data32_sel equ 10h ;2,gdt,rpl=00
gdt_entries equ 3 ;共有3个段描述符:null,os code32,os data32,
idt_entries equ 47
gdt_table equ pdescr + 6
idt_table equ pdescr + 6 +3*8
kb equ pdescr + 6 +3*8 + 33*8 ;键盘中断的段 在irq1,32+1=33,294=0x126
tm equ pdescr + 6 + 3*8 + 32*8 ;时钟中断的段,在irq0
ms equ pdescr + 6 + 3*8 + 44*8 ;鼠标中断的段,鼠标在irq12 32+12=44
woll equ 0x500000
[SECTION .text]
_addin: ;入口
pushad
jmp main
default_hand:
;默认中断处理函数 在256个中断里大部分用此中断,什么也不做就返回
;告诉硬件,中断处理完毕,即发送 EOI 消息
mov eax, 0x500000
mov word[eax],04321h ;在 0x500000处留下足迹,
;运行调试模式,c,程序结束, 先敲击键盘几下,ctrl+c退出程序,通过 x/10 0x500000查看
mov al , 0x20
out 0x20 , al
out 0xa0 , al
iret
time_hand:
;时钟中断处理函数
mov eax, 0x500000
mov word[0x500000+8],09876h ;在 0x500000处留下足迹,
mov al , 0x20
out 0x20 , al
out 0xa0 , al
iret
keyboard_hand:
;键盘中断处理函数。
;告诉硬件,中断处理完毕,即发送 EOI 消息
inc word[woll+2] ;将0x500002处字作为计数中断次数,一次键击产生两次计数。
mov ebx,0x500007
add bx,word[woll+2]
mov dx,0x60
in al,dx ;接受键盘输出值
mov byte[ebx],al ;从0x500008开始处留下中断扫描码
mov word[0x500004],0abcdh ;在 0x500004处留下足迹,
;运行调试模式,命令窗口,c,转到主窗口, 敲击键盘几下,转到命令窗口,ctrl+c退出程序,通过 x/10 0x500000查看
pushad
call _keyboard_interrupt_handle
mov al , 0x20
out 0x20 , al
out 0xa0 , al
popad
iret
mouse_hand:
;时钟中断处理函数
mov eax, 0x500000
mov word[0x500000+12],01515h ;在 0x500012处留下足迹,
mov al , 0x20
out 0x20 , al
out 0xa0 , al
iret
init_8259A:
;发送 ICW1 : 使用 ICW4,级联工作
mov al,011h
out 020h,al ;主8259,ICW1
out 0A0h,al ;从8259,ICW1
;发送 ICW2,中断起始号从 0x20 开始(第一片)及 0x28开始(第二片)
mov al,020h ;IRQ0 对应中断向量0x20
out 021h,al ;主8259,ICW2
mov al,028h ;IRQ8 对应中断向量0x28
out 0A1h,al ;从8259,ICW2
mov al,04h ;在IRQ2与从8259相连
out 021h,al ;主8259,ICW3
mov al,02h ;对应主8259的IRQ2
out 0A1h,al ;从8259,ICW3
mov al,01h
out 021h,al ;主8259,ICW4
out 0A1h,al ;从8259,ICW4
mov al,11111101b;屏蔽主8259,不屏蔽,IRQ1键盘外所有中断
out 021h,al ;主8259,OCW1
mov al,0xff ;屏蔽从8259所有中断
out 0A1h,al ;从8259,OCW1
ret
main:
;built up GDT table
cli
;初始化8259A
call init_8259A
mov eax,gdt_table
;item 0:null descriptor,
mov dword[eax],0
mov dword[eax+4],0
add eax,8
;item 1,OS code32 descriptor,
;Base=00000000h,limit=0ffh,G=1,D=1,type=a,dpl=0
mov word[eax],0ffh
mov word[eax+2],0
mov byte[eax+4],00h
mov byte[eax+5],09ah
mov byte[eax+6],0c0h
mov byte[eax+7],00h
add eax,8
;item 2,OS data32 descriptor
;Base=00000000h,Limit=0fffffh,G=1,D=1,Type=2,DPL=0
mov word[eax],0ffffh
mov word[eax+2],0000h
mov byte[eax+4],00h
mov byte[eax+5],092h
mov byte[eax+6],0cfh ;高四位是G D 0 AVL,此处为1100 = c ,低四位是limit bit 16-19 此处为f
mov byte[eax+7],00h
add eax,8
;built false GDT descriptor
mov word[pdescr+0],(gdt_entries*8)
mov dword[pdescr+2],gdt_table
lgdt [pdescr]
;建中断门
mov eax,idt_table
mov ebx,default_hand
mov word[eax],bx ;offset 15:0 在于0x801e 显示0x0c4e
mov word[eax+2],os_code32_sel
mov byte[eax+4],00h ;000 + 五位保留 = 00h
mov byte[eax+5],8eh ;高四位是 P=1 DPL=00 0 此处为1000 =8 ,低四位是 D=1 110 =E
shr ebx,16
mov word[eax+6],bx ;offset 31:16 显示0x0008 与前面合成地址为 0x80c4e
;fill all IDT table with default item
mov esi,idt_table
mov edi,(idt_table+8)
mov ecx,(idt_entries-1)*2
rep movsd
;IRQ0 定时计数
mov eax, tm
mov ebx, time_hand
mov word[eax],bx ;offset 15:0 在0x8 显示0x
shr ebx,16
mov word[eax+6],bx ;offset 31:16 显示0x0008 与前面合成地址为
;IRQ1 键盘 其表地址在 pdescr + 6 +3*8 + 33*8 将其处理程序地址填上keyboard_hand
mov eax, kb
mov ebx, keyboard_hand
mov word[eax],bx ;offset 15:0 在0x8126 显示0x0c5f
shr ebx,16
mov word[eax+6],bx ;offset 31:16 显示0x0008 与前面合成地址为 0x80c5f
;built false GDT descriptor for 中断
mov word[pdescr+0],(idt_entries*8)
mov dword[pdescr+2],idt_table
lidt [pdescr]
sti ;开中断
popad
ret
keyboard.c
#include "..\include\graph.h"
void keyboard_interrupt_handle() ;
unsigned short color ;
unsigned int x = 250 ;
unsigned int y = 80 ;
//扫描码与数字及字母对应的一维数组
char ch[51]={'A','B','1','2','3','4','5','6','7','8','9','0','C','D','E','F','q','w','e','r','t','y','u','i','o','p','G','H','I','J','a','s','d','f','g','h','j','k','l','K','L','M','N','O','z','x','c','v','b','n','m'} ;
// 键盘中断处理函数
char *b = (char *) 0x500008; //0x500008处有扫描码,这个是初始值,在中断之前赋一个初始值,随着键盘中断增加,这个值也要增加,所以把它拿出来在中断例程之外。
void keyboard_interrupt_handle() {
//写字的颜色
color = rgb_mix( 0 , 200 , 100 ) ;
int i ;
unsigned char ch2 = *(b +0) ;
unsigned char lo4,hi4 ;
hi4 = (ch2 & 0xf0) >> 4;
lo4 = ch2 & 0x0f;
i = hi4*16+lo4 ;
if(i<52){ //超出数组下标的乱码不显示
ya_draw_english( x, y, ch[i] , color ) ;
x=x+10 ;
}
b=b+1; //b值随着中断增加,以便显示下一个字
}
makefile
######################
#声明要编译的所有组成,这里的ya是本工程名称,可以取任何名字,这里就用ya
######################
ya:out/boot.bin out/kernelloader.bin out/kernel.asmo out/kernel.o out/graph.o out/keyboard.o out/kernel.ld out/kernel.bin out/addinter.asmo out/creat_img.exe out/write_in_img.exe A B C D E F G H
#开始对各部分编译,注意不是空格是Tab键
out/boot.bin:code/boot.asm
nasm code/boot.asm -o out/boot.bin
out/kernelloader.bin:code/kernelloader.asm
nasm code/kernelloader.asm -o out/kernelloader.bin
# 编译asm文件,生成中间文件
out/kernel.asmo:code/kernel.asm
nasm -f aout code/kernel.asm -o out/kernel.asmo
out/addinter.asmo:code/addinter.asm
nasm -f aout code/addinter.asm -o out/addinter.asmo
# 编译C文件,生成中间文件
out/kernel.o:code/kernel.c
gcc -fpack-struct -std=c99 -c code/kernel.c -o out/kernel.o
out/graph.o:code/graph.c
gcc -fpack-struct -std=c99 -Wno-packed-bitfield-compat -c code/graph.c -o out/graph.o
out/keyboard.o:code/keyboard.c
gcc -fpack-struct -std=c99 -Wno-packed-bitfield-compat -c code/keyboard.c -o out/keyboard.o
# 链接内核
out/kernel.ld:out/kernel.asmo out/kernel.o out/graph.o out/keyboard.o out/addinter.asmo
ld -Ttext 0x80000 -e start -o out/kernel.ld out/kernel.asmo out/kernel.o out/graph.o out/keyboard.o out/addinter.asmo
# 生成可执行代码文件
out/kernel.bin:out/kernel.ld
objcopy -R .note -R .comment -S -O binary out/kernel.ld out/kernel.bin
# 制作内核映象文件
out/creat_img.exe:code/creat_img.c
gpp code/creat_img.c -o out/creat_img.exe
# 执行dos命令,在final目录下生成a.img文件
A:
out/creat_img.exe final/a.img
# 写入文件,argv[1]=目标文件 argv[2]=源文件 argv[3]=写入偏移量
#在DOS下用法: write.exe a.img kernelloader.bin 512
out/write_in_img.exe:code/write_in_img.c
gpp code/write_in_img.c -o out/write_in_img.exe
# 执行dos命令,向a.img写入代码,内容是boot.bin
# 写入磁盘位置从0偏移量起始,占1个扇区512字节
B:
out/write_in_img.exe final/a.img out/boot.bin 0
# 执行dos命令,向a.img写入代码,内容是kernelloader.bin
# boot.bin已经占用了512字节,写入磁盘位置从512偏移量起始,占2个扇区1024字节
C:
out/write_in_img.exe final/a.img out/kernelloader.bin 512
# 执行dos命令,向a.img写入代码,内容是asc16
# boot.bin+kernelloader.bin已经占用了512+1024 = 1536字节,写入磁盘位置从1536偏移量起始
D:
out/write_in_img.exe final/a.img charpic/asc16 1536
E:
out/write_in_img.exe final/a.img charpic/hzk16f 5632
F:
out/write_in_img.exe final/a.img charpic/ya.bmp 267776
G:
out/write_in_img.exe final/a.img charpic/faya.bmp 361984
H:
out/write_in_img.exe final/a.img out/kernel.bin 479232
######################
bochsrc.bxrc (for Bochs-2.6.8)
###############################################################
# bochsrc.txt file for flopy image.
###############################################################
# how much memory the emulated machine will have
megs: 32
# filename of ROM images
romimage: file=../BIOS-bochs-latest
vgaromimage: file=../VGABIOS-lgpl-latest
# what disk images will be used
floppya: 1_44=a.img, status=inserted
# choose the boot disk.
boot: a
# where do we send log messages?
log: bochsout.txt
程序运行效果如图:
键入type12345