写bootloader介绍

来源:互联网 发布:土建预算软件有哪些 编辑:程序博客网 时间:2024/04/29 23:38

这两个星期就写个loader就写了很久。开始是因为图像坑,后来又被读盘坑,现在又被跳转坑。。(几个月再来看..应该先老实的在软盘下写出来再弄U盘的...)

代码也卡在进入保护模式之后,跳转到内核的地方。。

所以我下面只能简单的讲一下保护模式到底是什么和写它的流程。


正题:

首先loader的作用是什么?

由于之前提到bootsector只有512字节,所以程序不能写大了,于是需要另外补充一个程序,所以让loader出现了。

其实现在的操作系统可以不用自己写loader了,完全可以直接用grub加载内核.

但是如果你准备自己写一个的话,我认为还是可以写的。

可以从简单的开始,先写个段式的。加载内核再加上页式存储以及相关的IDT,TSS等。


保护模式是什么?

简单来说保护模式就是通过给CPU寄存器中的数据赋值,来让CPU可以判断当前指令是否合法。所以在《一个》书中代码,通过将相关寄存器的位来置位,来让CPU知道某段程序是否可以读写。并且通过GDT表中属性,比如基址+长度的方式让CPU判断访问是否越界。(这里可以脑补操作系统段寄存器相关说明)

所以这里就很明确了,对于越界访问其实是通过硬件实现的.

包括这里要说明的一点就是很多国内教材上说操作系统都说段页式算法复杂,所以都以页的方式来实现的。其实只要你看过《一个》就知道,只要是X86的话,全部都是段页式的啊!!!段式是无法避免的!主流操作系统段基址都是0,而不是不用段!虽说x64上的段式相对来说作用小一点,但是毕竟X64也是扩展的X86,所以段式是一定要有的。


PS:

貌似如果先跳转到保护模式再跳回实模式,如果GDTR不变的话,实模式的寻址空间也会是4G...

这个我没实验,是看到某个帖子上讨论说的.欢迎大家实验~~~


如何进入保护模式?

这一点其实很容易就做到!《一个》上面写的很复杂!!!!(后面开始用C之后简洁了不少)

首先定义一段gdt段,然后根据相关位的说明,按照要求置位.这个可以用<一个>上面的代码.它的宏定义很好用.

再其实只用弄一个指向GDT段的指针(类似,但其实看源码就知道它是个结构体),然后将CR0最低位置1即可。

然后通过一个jmp   dword + 32位代码段地址:物理地址    即可。(即一个远眺转)

关键代码如下:

         lgdt    [GdtPtr]          cli          ; open the A20 Address         in      al,92h         or      al,00000010b         out     92h,al           ;change to protect mode         mov     eax,cr0         or      eax,1        mov     cr0,eax          jmp     dword   SelectorCode32: 0
这个A20地址线是个历史遗留问题,必须得打开。
GdtPtr则需要通过写入GDT表的首地址和长度,然后才能给gdtr寄存器。


PS;

关于页式存储.原来以为页式存储的的方式应该通过软件算法来解决.我看资料上面好像也没提到缺页的时候如何做.就以为是硬件自主解决缺页问题..但其实只要CPU所读的页,缺页保护标志P=0的话(就是不在内存中),就会产生#PF中断.所以最终还是通过软件算法来搞定页置换算法的..

还有,有个刷新页目录表cache的指令,是invlpg指令.当页的映射模式改变时,比如改变页大小什么的时候,一定要用这个指令刷新页目录表.不过绝大部分时候没必要改变吧..


自己写遇到的坑:

1.图形界面

开始本来就想写一个图形界面的。所以还没进入保护模式就想试着写。

于是在网上找到个BIOS中断大全(信息非常不全啊!!!),将背景颜色置为绿色。调整了显示模式。

这一步还没什么问题,但是你以为去A000:0000写数据就等着绝望吧。。。

并且我进入保护模式之后向里面写也没用...貌似这还涉及到VGA...学校图书馆居然一本相关书都没....!!!

写了两个下午都没写上去!!!看《30天自制操作系统》上面写的好简单有木有!!!但是完全没用啊!!

这本书真的是可以扔了。。不用它的工具基本你就废了。。真的只是让新手觉得好玩而已。。

书上的程序基本不算很难,也没太多理论方面的学习。。。

当然...也可以学一学他是如何优化程序的...


2.读盘坑

没错。。。boot之前都读好了盘,怎么到这里就不行了呢。。。。这也坑了我好几个下午!!!

最后发现,如果你用[BITS  16]之后貌似就不能用随便读盘啊!!!一直读盘错误!!!!

开关机都好几十次啊!!!我也不清楚是怎么回事。。估计是nasm编译上有区别。

所以就直接改bootsector代码,让它把内核的也读了。


3.跳转坑

这个最坑!!!搞了4天!!!还没搞出来!!!就只是从loader的保护膜式代码中跳到内核代码中去。。。仍然坑了我4天。。。各种方法都是试过了啊!!!先是调整加载的位置,不行。。。然后将c代码编译成纯二进制,不行。。。我用反汇编objdump查看二进制是否符合要求,结果符合。。。然后我又把数据段的属性各种改。。。还是不行。。。各种调整ld的链接方式有木有啊 !!!最后还是没解决...所以决定使用grub了...



吐槽:

由于写的X86的操作系统,网上资料说实话很少,大量的转载。。而且能用的非常少!好不容易找到一些资料,兴冲冲的抄下来编译,很多根本不能编译过!!!关键是还到处转载!!!而且很多没有真正读过《一个操作系统的实现》喜欢拿这本书说事,各种推崇。这反而让我觉得他们没有读懂这本书,或者说没有自己一行行代码的敲一遍..要你一行行写的话,又会发现这本书也有其不足...并且这本书很多代码也是借鉴来的,有很多地方并没有讲的很清楚。而且对于一个新手来说,它的部分内容过于复杂了。特别是对于没有学习过保护模式的人,看起来太艰难了。一次性就把GDT,LDT,IDT,TSS给一起说了。让人很想放弃。头一次看得稀里糊涂的。。如果不看上个三四遍,感觉是不太可能理解的..还有就是很多人在网上说自己怎么怎么准备写一个操作系统,吹得无比NB,最后也就写个bootsector。反倒很多大牛喜欢把自己的代码提交到国外网站上。。这让我这英语渣情何以堪。。当然,国外的资料还是蛮多的...就是看不懂.........................大牛们又不愿意公开写个博客记录过程,搞的弱菜们只能苦苦挣扎....


结尾:

好吧..正题没怎么详细写,吐槽写了不少....废话一大堆..我也只能起个引导的作用....关键还是得看书...

今天准备上grub引导的...本来想在U盘上装grub引导....不知怎么把笔记本的grub删了.....

没错是删了....连命令行界面都没了....顺便鄙视那些博客教人不教全的...

这一篇文章就当存个档了...内核我一定会写完的!!

也得把看Linux内核的计划提前了...基础还是太浅了..或许边看边写会比较好..

目前功力不足...还是先缓缓这个计划吧...

0 0
原创粉丝点击