用大白话说操作系统(四)

好的,OK,上次我们说到操作系统模式的转换,有一个gdt全局描述符表,段寄存器里面存储着段选择子,到gdt中找到段基址【全局描述符表通过gdtr找到它自己在内存中的位置】,这只是进入保护模式的一个准备工作,接下来我们看另一个准备工作。

mov al,#0xD1        ; command write
out #0x64,al
mov al,#0xDF        ; A20 on
out #0x60,al

在setup.s中有这样一段代码,他的意思是打开A20地址线。

打开A20地址线就是说,突破地址信号线20位的宽度,变成32位可用,8086在CPU只有20位地址线,可是很无奈,我们为了向下兼容还得保持20地址线的模式,只有手动开启32位地址线,才能使用32位地址线。说白了,为了使用能用的几种模式,我们就必须做这些烦人的操作。

之后,经过对可编程中断控制器8259芯片进行编程,我们得到8259芯片的引脚和中断号的对应关系如下。
在这里插入图片描述

mov ax,#0x0001  ; protected mode (PE) bit
lmsw ax      ; This is it;
jmpi 0,8     ; jmp offset 0 of segment 8 (cs)

上面三行代码实现了模式的切换。
前两行将cr0这个寄存器位0置1,模式就从实模式切换到保护模式了。
在这里插入图片描述
第三行有一个段间跳转地址,8表示代码段寄存器cs的值,0表示偏移地址,这里是保护模式下的寻址方式,也就说他是从内存地址为0的地方开始执行了。我们前面已经介绍过,内存地址为0的地方存放着我们的system模块,也就是操作系统最为主要的代码,是由head.s main.c以及其余各模块的操作系统代码合并来的。
boot文件夹下有三个汇编语言写的文件,bootsect.s setup,s以及head.s,我们已经读了前两个,再读完最后一个就看见曙光路。

head.s

好的,我们直接看这个代码。

_pg_dir:
_startup_32:
    mov eax,0x10
    mov ds,ax
    mov es,ax
    mov fs,ax
    mov gs,ax
    lss esp,_stack_start

_pg_dir:页目录,之后在设置分页机制时,页目录会存放在这里,也会覆盖这里的代码。
下面是连续5个mov操作,分别给ds es fs gs赋值为0x10,根绝段描述符结构解析,这几个段寄存器的值指向全局描述符表中的第二个段描述符,也就是数据段描述符。
lss:让ss:esp这个栈顶指针指向_stack_start这个标号的位置。栈顶指针是0x9ff00

call setup_idt ;设置中断描述符表
call setup_gdt ;设置全局描述符表
mov eax,10h
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
lss esp,_stack_start

这里设置了idt和gdt,也就是中断描述符表和全局描述符表,然后重新设置了寄存器的值,和上面的操作一毛一样。

setup_idt:
    lea edx,ignore_int
    mov eax,00080000h
    mov ax,dx
    mov dx,8E00h
    lea edi,_idt
    mov ecx,256
rp_sidt:
    mov [edi],eax
    mov [edi+4],edx
    add edi,8
    dec ecx
    jne rp_sidt
    lidt fword ptr idt_descr
    ret

idt_descr:
    dw 256*8-1
    dd _idt

_idt:
    DQ 256 dup(0)

中断描述符表idt里面存放着中段描述符,每一个中断号,对应一个中段描述符,中段描述符里面存放着中断程序的地址,就像段描述符里面存放着段基址一样。什么作用?也就是说你要中断就拿一个中断号过来,我根据中断号找到你的中段描述符,然后找到中断程序的地址。
这段代码设置了256个中段描述符,每一个中段描述符中的中断程序例程都指向一个ignore_int的函数地址,这个是默认的中断处理程序,之后会被具体的中断程序覆盖。
现在你做的任何中断都会指向ignore_int,也就说你没有写具体的终端任务呢,设置中断也不好使!!!

set_gdt:
 DQ 0000000000000000h    ;/* NULL descriptor */
 DQ 00c09a0000000fffh    ;/* 16Mb */
 DQ 00c0920000000fffh    ;/* 16Mb */
 DQ 0000000000000000h    ;/* TEMPORARY - don't use */
 DQ 252 dup(0)

这里我们还需要设置全局描述符表,大家可能有些疑惑,之前已经在setup.s中设置过了,但是之后setup.s可能会被新的代码覆盖,所以我们head.s还要重新设置一遍。
还是0号描述符为空,1号为代码段描述符,2号位数据段描述符,3号没有设置,最后保留了252项空间放置任务状态段描述符TSS和局部描述符LDT。

jmp after_page_tables
...
after_page_tables:
 push 0
 push 0
 push 0
 push L6
 push _main
 jmp setup_paging
L6:
 jmp L6

这里的代码开启了分页机制,并且跳转到main函数,这样我们就可以读C的代码了,真实的是一个不容易了!!!!
好的,OK,今天说到这里,有问题欢迎评论区留言。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙诙谐代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值