Open GoogleCodeExporter opened 9 years ago
> New issue report by earthengine:
>
1、目前叙述Loader的部分篇幅过大。其实,这部分代码是完全�
��必要的。因为
>
Grub/LILO/Syslinux等优秀的Loader已经存在,我们没有必要重新发��
�轮子。
>
>
我们需要的,是让代码兼容于Linux内核,使得Loader能够识别并
加载我们的操作系
> 统。为此,需要向读者介绍Linux Boot
Protocol。这方面,我已经做了一些研究,已
>
经有简化的代码片段可以编写一个最小的(1K字节)的内核,
完全兼容Grub/LILO
> /SysLinux,甚至可以用Qemu直接载入。
事实上,我原来的思路是从 0
开始,而且我没有打算写一个大而全的 OS,因为我们
有了 Linux,读者如果有能力去了解
Linux,就不用来看本书。现在的操作系统教材
往往是从抽象层面讲
OS,而不是切切实实地讲到每一个细节。如果按照你的思想来
说,
《现代操作系统》这本书就足够了,而我这本书的初衷和它��
�然是不一样的,也不会去
试图覆盖《现代操作系统》的一些东西。
>
2、软盘镜像有点过时了,而且需要用不完全自由的FAT格式(�
��知道微软什么时候会
>
发神经收专利费,尽管现在大家都在用)。我写的一个Project�
��成的是完全开放的
>
iso镜像,同样可以让虚拟机直接加载,并显得更专业。iso镜��
�使用isolinux启动,
>
从而避免自行编写复杂的cdrom启动代码(再次强调,我们要写
的是OS,不是OS
> Loader,不要喧宾夺主)。
这方面我承认,囿于知识的贫乏,我没能去使用 ISO
镜像。对于您的最后意见,我还是
不太同意,我希望这本书尽量地覆盖一些底层的细节,因为��
�些细节往往是那些讲解操作
系统的书所忽略的,读者很难从别的地方找到。
>
3、VirtualBox尽管有好用的图形界面,但有一点比不上Qemu,就��
�不支持内核的直接
> 载入。在这方面Qemu非常好,直接qemu -hda /dev/zero -kernel
myos就可以加载内
>
核镜像。这真是太方便了,甚至可以写到Makefile里面,直接mak
e qemu就能完成编译
> 并加载到qemu测试。
同样是知识所限,我当时没有选择
Qemu。至于虚拟机,其实我觉得选择哪个都无所谓,每个
软件总有自己的长处和短处,比如 Bochs
支持系统级的调试,也是它的一大优点,读者其实
是可以自由选择的。
>
4、我觉得,应该向读者介绍更多的自由软件开发常规。例如A
utoconf/Automake等,
>
并适当引入SVN版本管理。编写OS毕竟不是小工程,应该从一开
始就有正确的管理,因
> 此这些技术都是必须要用到的。
事实上,我打算写的是一本书,而不是一个操作系统,那个��
�作系统的代码完全是为书服务
的,所以这个操作系统不可能很大,这样会使读者望而生畏��
�像现在的 Linux 代码那样。
等这本书结束的时候,这个操作系统也不大可能是一个实用��
�操作系统,所以这些复杂的
工具大概不会用到。
从您的意见来看,我感觉我们两个最大的不同是对这个操作��
�统作用的理解。您是希望这个
操作系统成为一个能持续发展,不断完善的实用操作系统,��
�这本书成为一个注脚;我是
希望这个操作系统保持尽量的简洁,为书中所介绍的知识服��
�,当读者读完这本书时,只会
拿到一个实验性质的几乎无用的
OS,但是他所积累的知识会有助于他去理解 Linux/Minix
这样一些复杂的操作系统。
以上是我的意见,欢迎拍砖!
Original comment by solrex
on 16 Oct 2008 at 10:57
我设想以此节取代原2.2 FAT的介绍
2.2 Linux 启动协议
上一节,我们介绍了如何编写引导扇区并将它写入引导软盘的合适位置,以便我们的代码
能够被BIOS加载。无疑这是编写真正操作系统的第一步,但是�
��们必须明白,即使是这一步也不
是那么简单的。从软盘引导也许是最简单的了,但实际应用��
�时候,我们的操作系统必须能够从
各种不同的介质加载:从硬盘,从光驱,从老式的ZIP驱动器��
�从USB外置硬盘,从U盘……要是一一
编写启动代码,这无疑有相当的工作量。
幸好,不需要重新发明轮子!我们有各种各样的“引导加载器”可以用来加载引导代码。例
如,如果你用过任何眼下流行的Linux发行版,你多半是用Grub��
�载系统的。如果你用过Linux
Live
CD,那么你也许知道有个isolinux可以引导光盘上的Linux。如果��
�用Linux多年,知道一些
掌故,那么你也会知道以前的Linux发行版用LILO来引导系统。��
�要注意的是这些引导加载器不一
定只能加载Linux,例如很多发行版都提供一个内存检测工具mem
test86,这个并不是Linux,但同
样可以被加载器加载。
所以,我们不需要过多了解引导加载器如何识别各种各样的启动环境。但是有一个问题仍
然必须解决:必须让引导加载器能够识别我们的“操作系统��
�代码。这样,就需要了解Linux启动协
议,因为所有兼容Linux的引导加载器必须和这个协议兼容,所
以只要我们遵守了这套协议,就能
让Linux识别我们的引导加载器。
下面,我们从样板代码开始,看看符合Linux启动协议的“内核
”应该具有什么样的结构。
start:
jmp .
.org 497
setup_sects: .byte _setup_sects
root_flags: .2byte 1
syssize: .4byte _file_length
ram_size: .2byte 0
vid_mode: .2byte 0xffff
root_dev: .2byte 0
boot_fliag: .2byte 0xaa55
.text
.code16
jmp OS_START
header_magic: .ascii "HdrS"
version: .2byte 0x200
realmode_swtch: .4byte 0
start_sys: .2byte 0
kernel_version: .2byte 0
type_of_loader: .byte 0
loadflags: .byte 0
setup_move_size: .2byte 0
code32_start: .4byte 0
ramdisk_image: .4byte 0
ramdisk_size: .4byte 0
bootsect_kludge: .4byte 0
head_end_ptr: .2byte 0
.2byte 0
cmd_line_ptr: .4byte 0
initrd_addr_max: .4byte 0
kernel_alignment: .4byte 0
relocatable_kernel: .byte 0
.2byte 0
.byte 0
cmdline_size: .4byte 0
hardware_subarch: .4byte 0
hardware_subarch_data: .8byte 0
OS_START:
/*Start point, default address is 9020:0000,but it is not compatible with the
la*/
ljmp $0x9000,$prog_start
历史上,Linux内核是可以直接拷贝到软盘从引导扇区开始的位
置上,然后从该软盘启动的。但是
新版本的内核已经不再支持这种方式。但是作为历史遗留问��
�,内核的第一个扇区总是留给引导
扇区。而引导扇区需要带有一个引导程序。在这里,为了简��
�代码,简单地用一个死循环开始。
引导扇区中间的部分是什么都不重要,因此接下来的org
497是要跳过中间的字节,直接跳到第
497个字节去。在这里,正确设置setup_sects和syssize这两个字段��
�常重要。前者是内核的“初
始化代码”所占用的扇区数目,而后者是整个内核的大小(��
�须为512的整数倍)。其余字段都有
相对固定的值,目前你只要按照上面的方式赋值即可。
但是计算syssize和setup_sects并不简单。因为内核的大小会随着��
�们程序开发的进度变化,如
果每次编译都要回头手工设置这两个值,那也太麻烦了。幸��
�,连接脚本可以为我们做到这个:
SECTIONS
{
. = 0;
.bs :
{
} = 0
. = 512;
.text :
{
_ftext = .;
} = 0
.end :
{
. = ALIGN(512);
}
_file_length = ALIGN(512);
_setup_sects = ALIGN(512) / 512 -1;
}
上面这个连接脚本指出:连接程序会遇到3个不同的段,分别�
��名为.bs,.text和.end。在加载
了.bs段后,要把当前位置设置到512。所以.bs段的大小就正好��
�512,而不管它实际上可能占不
满。在.text段之后的.end段,要把当前位置对齐到512字节,这��
�,.text段的长度就总是512字
节的整数倍。最后,我们要求连接程序计算两个变量的值。��
�两个变量的值在汇编代码里面是声
明为extern的,汇编器生成的目标代码中这里是空位。这样,��
�接程序在分析了连接脚本之后,
首先就会生成一个布局,然后把计算出来的变量值填充到空��
�里。这样就完成了设置这些关键变量。
现在,我们来看看内核是如何加载到内存的。启动协议规定��
�载点是0x9000:0000。但是要注意的
是,这个位置是引导扇区和所有setup_sects加载到的位置。引导
加载程序会跳过引导扇区,因此
实际的加载点是0x9020:0000。但是这里有一个问题,就是在代码
里面的标号和字符串地址等的值
是加上了512的,并不是从0开始。所以,我们需要一段设置段�
��存器的代码,用来标准化段的引
用,使得此后对地址的引用能够正确。
OS_START:
/*Reset the CS,DS,ES & SS, Set SP to $1000*/
ljmp $0x9000,$prog_start
prog_start:
mov %cs,%ax
mov %ax,%ds
mov %ax,%es
mov %ax,%ss
mov $0x1000,%sp
我们首先执行一个段间跳转,使CS段寄存器固定为0x9000,这样
所有的标号都有了正确的偏移
量。此后,我们把CS的值传到其它段寄存器。最后,设置一下
堆栈指针。
Original comment by earthengine
on 16 Oct 2008 at 2:16
我同意solrex的看法。
作为一个能发展的操作系统,需要的东西实在太多了。
最低限度,一个能发展的操作系统至少要有一个编译器吧。��
�里就会耗掉至少10w行代码。
文字编辑器呢,好像也是必须要的,不可能为了用vim或者emacs
还需要切到linux写代码吧。
然后shell、更强壮的文件系统、多处理器支持、更强壮的内存
管理、甚至在这个年代必需一从头
就考虑的64位机。
--到时候会发现所有的东西都缺。难道要把这些全从linux迁移�
��去?
就像侯捷先生在深入浅出MFC里面那样,做一个无用的操作系��
�。
但读者学到的东西确实是有用的。
ps.如果这个操作系统还没有名字的话,我建议取做μOS(/mu OS)
Original comment by yegong1...@gmail.com
on 7 Nov 2008 at 8:09
Original issue reported on code.google.com by
earthengine
on 16 Oct 2008 at 10:36