setup.asm上一篇文章中的setup是用于测试的,不是linux中的setup。现在给出linux中的setup的源代码(nasm实现)
;;setup.asm
[section .data]
INITSEG equ 0x9000
SYSSEG equ 0x1000
SETUPSEG equ 0x9020
[section .text]
mov ax,INITSEG ;将系统数据放到0x90000处
mov ds,ax
mov ah,0x03 ;获取光标的位置
xor bh,bh
int 0x10
mov [0],dx
mov ah,0x88 ;获取扩展内存大小
int 0x15
mov [2],ax
mov ah,0x0f ;获取显卡当前显示模式
int 0x10
mov [4],bx
mov [6],ax
mov ah,0x12 ;获取EGA/VGA的显示模式及参数
mov bl,0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx
mov ax,0x0000 ;复制第一个硬盘的参数表到0x90080处
mov ds,ax
lds si,[4*0x41]
mov ax,INITSEG
mov es,ax
mov di,0x80
mov cx,0x10
rep
movsb
mov ax,0x0000 ;复制第二个硬盘的参数表到0x90090处
mov ds,ax
lds si,[4*0x46]
mov ax,INITSEG
mov es,ax
mov di,0x90
mov cx,0x10
rep
movsb
mov ax,0x1500 ;检查是否存在第二个硬盘,如果不存在,
mov dl,0x81 ;将0x90090处的第二个硬盘的参数表清零
int 0x13
jc no_disk1
cmp ah,0x3
je is_disk1
no_disk1:
mov ax,INITSEG
mov es,ax
mov di,0x0090
mov cx,0x10
mov ax,0x00
rep
stosb
is_disk1:
;现在要进入保护模式
cli
mov ax,0x0000
cld
;首先把system从0x10000处移动到0x00000处
do_move:
mov es,ax
add ax,0x1000
cmp ax,0x9000
jz end_move
mov ds,ax
sub di,di
sub si,si
mov cx,0x8000
rep
movsw
jmp do_move
end_move:
mov ax,SETUPSEG
mov ds,ax ;将idt表,gdt表的信息加载到相应的寄存器
lidt [idt_48]
lgdt [gdt_48]
call empty_8042 ;打开A20地址线
mov al,0xD1
out 0x64,al
call empty_8042
mov al,0xDF
out 0x60,al
call empty_8042
mov al,0x11 ;初始化8259,设置ICW1
out 0x20,al
dw 0x00eb,0x00eb
out 0xA0,al
dw 0x00eb,0x00eb
mov al,0x20 ;设置ICW2
out 0x21,al
dw 0x00eb,0x00eb
mov al,0x28
out 0xA1,al
dw 0x00eb,0x00eb
mov al,0x04 ;设置ICW3
out 0x21,al
dw 0x00eb,0x00eb
mov al,0x02
out 0xA1,al
dw 0x00eb,0x00eb
mov al,0x01 ;设置ICW4
out 0x21,al
dw 0x00eb,0x00eb
out 0xA1,al
dw 0x00eb,0x00eb
mov al,0xFF ;设置OCW1
out 0x21,al
dw 0x00eb,0x00eb
out 0xA1,al
mov ax,0x0001 ;置cr0的第0位为1,表示进入保护模式
lmsw ax
jmp 8:0 ;跳到cs段8,偏移0处,此时已启动保护模式,即0x00000处
;system的最开始位置
empty_8042:
dw 0x00eb,0x00eb
in al,0x64
test al,2
jnz empty_8042
ret
gdt:
dw 0,0,0,0 ;第一个描述符,不用
dw 0x07FF ;code 段的描述符,段长=2048*4096=8M
dw 0x0000 ;base address=0
dw 0x9A00 ;code read/exec
dw 0x00c0 ;granularuty=4096,386
dw 0x07FF ;data 段的描述符,段长=2048*4096=8M
dw 0x0000 ;base address=0
dw 0x9200 ;data read/write
dw 0x00c0 ;granularuty=4096,386
idt_48:
dw 0
dw 0,0
gdt_48:
dw 0x800
dw 512+gdt,0x9 ;0x90200+gdt
用于测试的system.asm 因为此时不能用bios中断了,所以要改一下system
bits 32
[section .text]
mov ax,cs
mov es,ax
mov ax,0x10
mov gs,ax
mov edi,(80 * 11 + 0)*2 +0xb8000
mov ah,0Ch
mov al,'f'
mov [gs:edi],ax
jmp $
把setup.asm和system.asm编译成.bin文件,再按照上一篇文章的方法执行。
结果图: