;我们的启动程序实现的功能是在屏幕中央
;打印一行字符串即可
[BITS 16]
org 07c00h ;指令明确告诉编译器我程序的段地址是7c00h
;而不是原来的 00000
; int汇编指令 int 10h
jmp main
gdt_table_start:
gdt_null:
dd 0h
dd 0h ;Intel 规定段描述符的第一个表项
;必须这样表示
gdt_data_addr equ $-gdt_table_start
gdt_data:
dw 07ffh ;段界限
dw 0h ;段基地址0-18位
db 0h ;段基地址19-23位
db 10010010b ;段描述符的第六个字节
db 11000000b ;段描述符的第七个字节
db 0 ;段描述符的最后一个字节
;也就是段基地址的第二部分
gdt_video_addr equ $-gdt_table_start
gdt_video: ;用来描述显存地址空间的段描述符
dw 0FFh ;显存段界限就是1M
dw 8000h
db 0Bh
db 10010010b
db 11000000b
db 0
gdt_code_addr equ $-gdt_table_start
gdt_code:
dw 07ffh ;段界限
dw 1h ;段基地址0-18位
db 80h ;段基地址19-23位
db 10011010b ;段描述符的第六个字节
db 11000000b ;段描述符的第七个字节
db 0 ;段描述符的最后一个字节
;也就是段基地址的第二部分
gdt_table_end:
gdtr_addr:
dw gdt_table_end-gdt_table_start-1 ;段描述符表的长度
dd gdt_table_start ;段描述符表基地址
; lgdt [gdtr_addr] ;让cpu读取gdtr_addr所指向的内存内容
;A20地址线问题
main:
;初始化数据段描述符的基地址
xor eax,eax
add eax,data_32
mov word [gdt_data+2],ax
shr eax,16
mov byte [gdt_data+4],al
mov byte [gdt_data+7],ah
;初始化代码段描述符的基地址
xor eax,eax
add eax,code_32
mov word [gdt_code+2],ax
shr eax,16
mov byte [gdt_code+4],al
mov byte [gdt_code+7],ah
cli ;废除原来的中断向量表
lgdt [gdtr_addr] ;让cpu读取gdtr_addr所指向的内存内容
enable_a20:
in al, 92h
or al, 00000010b
out 92h,al
;设置cr0寄存器的第一位为1
mov eax,cr0
or eax,1
mov cr0,eax
;跳转到保护模式中
jmp gdt_code_addr:0
[BITS 32]
;保护模式的功能是在屏幕中央打印hello world
data_32:
db "hello world"
code_32:
mov ax,gdt_data_addr
mov ds,ax
mov ax,gdt_video_addr
mov gs,ax
mov cx,11
mov edi,(80*10+12)*2; 在屏幕中央显示
mov bx,0
mov ah,0Ch
s: mov al,[ds:bx]
mov [gs:edi],al
mov [gs:edi+1],ah
inc bx
add edi,2
loop s
jmp $
times 510-($-$$) db 0
dw 0aa55h
阅读(441) | 评论(0) | 转发(0) |