注意啊,没看下面的文章的要先看看下面的,再看这一篇啊。
我们刚才成功从启动层跳转到了内核程序,现在就应该从内核程序执行C语言了。但是,由于现在的CPU处于实模式中,而我们计划使用保护模式,所以要先切换过来。
在实模式中,我们只可以使用1MB以下的内存,所以我们需要先打开这个。
具体讲解如下。
首先我们要屏蔽所有的中断。万一哪个用户在切换CPU模式的时候碰了一下鼠标,就不好办了。所以,我们需要禁用所有中断。
完成以上命令只需要几行程序。
; 禁用所有PIC中断
; 由于OUT指令的第二个操作数(数据)必须是寄存器
mov al, 0xff
; 将0xff发送给PIC(0xff代表全部的一,禁用所有中断)
; 0x21是主PIC的端口
out 0x21, al
; 如果连续执行out指令,有的CPU无法执行
nop
; 然后禁用来自从PIC的中断
out 0xa1, al
; 禁止CPU级别的中断
cli
哎,大家可能只有在看笔者的程序时才会看到注释比程序还要多的情况呢。
接下来,我们要让CPU可以使用1MB以上的内存。这是因为CPU为了兼容以前的操作系统,在激活之前只可以使用1MB的内存。
; 下面的内容是函数,应确保CPU不会擅自执行
wait_KBD_out:
; 读取PIC中积攒的数据
in al, 0x64
and al, 0x02
; 清空垃圾数据
in al, 0x60
; 如果AND指令的结果不是0就重新跳转到wait_KBD_out
; Jump if not zero(不是零则跳转)
jnz wait_KBD_out
; 返回
ret
; 让CPU能访问1MB以上的内存
; 读取
call wait_KBD_out
; 数据
mov al, 0xd1
; 发送信号
out 0x64, al
; 读取
call wait_KBD_out
; 启用的信号
mov al, 0xdf
; 发送信号
out 0x60, al
; 继续读取
call wait_KBD_out
然后,CPU就可以访问1MB以上的内存了。
接下来,我们要让CPU切换到保护模式。
切换到保护模式只需要让CPU中CR0寄存器的bit0为1就可以了。当然,在此之前,我们要先设定临时的GDT。
; 以下是数据段,也要确保CPU不会擅自执行
; 判断地址是否可以被16整除
alignb 16
tmp_gdt:
; 空
resb 8
; 可读写的段,32bits
dw 0xffff, 0x0000, 0x9200, 0x00cf
; 可执行的段,32bits(C程序用)
dw 0xffff, 0x0000, 0x9a28, 0x0047
gdtr0:
; 很简单的程序,看不懂就不要看了
dw 8 * 3 - 1
; tmp_gdt的内容
dd tmp_gdt
; 判断地址是否可以被十六整除
alignb 16
; 设置临时的GDT
lgdt [gdtr0]
; 读取Control Register 0的内容到EAX寄存器中
mov eax, cr0
; 设置EAX寄存器的值
; 设置bits31为0(为了禁止分页,我们想要使用分段)
and eax, 0x7fffffff
; 设置bit0为1(切换到保护模式)