##版本0.2 设置IDT,开启时钟中断
代码如下
kernel.asm
; nasm -f elf kernel.asm -o kernel.o; ld -s -Ttext 0x10000 kernel.o -o kernel.bin ; dd if=kernel.bin of=a.img bs=512 seek=1 conv=notrunc[section .text][bits 32]global _start_start: mov ax, 16 mov ds, ax mov es, ax mov ss, ax mov esp, 0x7c00 mov ax, 24 mov gs, ax lidt [idtptr] call print call init8259a stiend: jmp endprint: mov edi, (80 * 11 + 79) * 2 mov ah, 0x0c mov al, 'K' mov [gs:edi], ax ret_clock:clock equ _clock - $$ + 0x10000 ; 0x10000就是ld中的入口地址 inc byte [gs:((80 * 11 + 79) * 2)] mov edi, (80 * 11 + 78) * 2 mov ah, 0x0c mov al, 'I' mov [gs:edi], ax mov al, 0x20 out 0x20, al iretdinit8259a: mov al, 0x11 out 0x20, al call io_delay out 0xa0, al call io_delay mov al, 0x20 out 0x21, al call io_delay mov al, 0x28 out 0xa1, al call io_delay mov al, 0x04 out 0x21, al call io_delay mov al, 0x02 out 0xa1, al call io_delay mov al, 0x01 out 0x21, al call io_delay out 0xa1, al call io_delay mov al, 11111110b ; out 0x21, al call io_delay mov al, 11111111b out 0xa1, al call io_delay retio_delay: nop nop nop nop retidt:%rep 255 dw (clock & 0xffff) dw 8 dw 0x8e00 dw (clock >> 16)%endrepidtlen equ $-idtidtptr dw idtlen-1 dd idt
通过readelf -a kernel.bin, 可以知道.text的大小是0x8ac,4个多扇区,所以直接读入内存5个扇区。
bootsect.asm
; nasm bootsect.asm -o bootsect.bin; dd if=bootsect.bin of=a.img bs=512 count=1 conv=notruncorg 0x7c00jmp startgdt: dw 0 dw 0 dw 0 dw 0gdt_code: ; 基址为0,大小4GB的32位可执行代码段 dw 0xffff dw 0x0000 dw 0x9a00 dw 0x00cfgdt_data: ; 基址为0,大小4GB的32位可读写数据段 dw 0xffff dw 0x0000 dw 0x9200 dw 0x00cfgdt_video: ; 基址为0xb8000,大小64KB的可读写显存段 dw 0xffff dw 0x8000 dw 0x920b dw 0x0000gdtlen equ $ - gdtgdtptr dw gdtlen -1 dd gdtstart:; 利用0x13号BIOS中断,将软盘kernel.bin中的.text读入内存0x1000:0x0000(实模式)。 mov ax, 0x1000 mov es, ax mov bx, 0 mov ax, 0x0205 ; 读入5个扇区 mov cx, 0x000a mov dx, 0 int 0x13into_kernel: ; 加载GDT lgdt [gdtptr] ; 关中断 cli ; 开启A20线 in al, 0x92 or al, 00000010b out 0x92, al ; 打开保护模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 进入保护模式 jmp dword 0x8:0x10000 ; 0x8, 可执行代码段gdt_codefill: times 510-($ - $$) db 0 dw 0xaa55