LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 59948|回复: 104

Grub 源代码分析

[复制链接]
发表于 2005-1-11 17:01:12 | 显示全部楼层 |阅读模式
这个主题源自westroom兄的意见。

我是第一次写这种“标题庄重”的技术文章,感觉好怕怕的,大家一起来写这个吧!
版本就用0.93的吧,我手头正好有这个版本。

其实总体上我们可以把grub看成一个mini os,他有shell,支持script,有文件系统……
我们可以把stage1 stage1-5看成一个boot loader,而stage2则是一个os,只不过这个os是专门load其他os的os,为此,stage2支持像kernel,initrd,chainloader等等为此目的而设置的内部“命令”……

(自己看书的时候常常跳过前言,觉得很多书的前言绪论实在让人厌烦,等看到正文的时候已经头晕目眩了,所以写这么多的介绍性文字已经是我的极限了,权当作抛砖引玉的作用,后面会陆续写些详细的分析文章,大家有兴趣可以一起写写)
 楼主| 发表于 2005-1-11 17:39:03 | 显示全部楼层
1.简略流程
(如果你不熟悉grub,建议您先看完这这一节再向后)
a,Bios执行int 0x19,加载MBR至0x7c00并跳转执行。
     如果你安装grub到mbr,grub的安装程序会把stage1(512B)拷贝到mbr。
     视stage2的大小,安装程序会在stage1中嵌入stage1-5或者stage2的磁盘位置信息。
b,stage1开始执行,它在进行直接加载stage1-5或者stage2并跳转执行(还有些额外的工作,这里忽略先)
     stage1-5很无辜,除了加载stage2以外它没有其他任何作用。
     所以,不论是哪种情况,这一步的结果都是stage2开始运行了。
c,stage2这个mini os终于开始正式运行了!它会把系统切入保护模式,设置好c运行环境(主要是bss)
     他会找config文件先(就是我们的menulist),如果没有的话就执行一个shell,等待我们输入命令。
     然后grub的工作就是输入命令-解析命令-执行命令的循环,当然stage2本身也很无辜,他是为加载其他os
    而存在的,所以如果情况允许,在他执行boot命令以后就会把控制权转交出去!


(已经尽量控制篇幅,还是超过预算,作为骨架性的一节,这应该是要常驻读者的“内存”的,所以还是显得太多了)
发表于 2005-1-11 22:43:05 | 显示全部楼层
版主可以将此版本的Grub 源代码给放上来吗?或者给出下载的连接好吗
关注。
 楼主| 发表于 2005-1-12 10:43:19 | 显示全部楼层
grub0.93

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2005-1-12 10:57:13 | 显示全部楼层
grub0.93

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2005-1-12 11:21:12 | 显示全部楼层
顶一个先哈!
 楼主| 发表于 2005-1-12 11:48:53 | 显示全部楼层

2 Stage2-文件系统

a,调用接口

类似系统调用,在stage2/disk_io.c中定义了grub_open,grub_close,grub_read,grub_dir
全局函数用于stage2的文件操作:打开,关闭,读,切换目录。

为了简化文件系统驱动的编写,grub不支持磁盘写(对于一个loader来说也没有必要去写磁盘)


b,文件系统驱动接口

任何一个文件系统驱动必须在fsys_table(stage2/disk_io.c)数组中去放置一个
struct fsys_entry的结构体,定义如下(stage2/filesys.h):
struct fsys_entry
{
  char *name;//文件系统名称
  int (*mount_func) (void);//初始化函数
  int (*read_func) (char *buf, int len);//文件读函数
  int (*dir_func) (char *dirname);//目录/文件打开函数
  void (*close_func) (void);//文件关闭函数
  int (*embed_func) (int *start_sector, int needed_sectors);//?大部分驱动设置此项为NULL
};


c,情景:读入文件

假设在grub的Menulist中有:kernel (hd0,0)/boot/vmlinuz(或者我们在grub shell中执行此命令)

stage2会先调用grub_open("(hd0,0)/boot/vmlinuz")来打开文件。
在执行这个函数中,grub会先在fsys_table中循环调用fsys_entry::mount_func去发现一个返回值为真的文件系统,即为当前的文件系统。然后利用当前文件系统驱动的fsys_entry::dir_func去打开/boot/vmlinuz
然后stage2会调用grub_read(buf,0)读入全部的/boot/vmlinuz文件至内存中的buf地址
grub_read是fsys_entry::read_func的封装。
最后stage2回调用grub_close关闭文件,跟前面一样,这个调用仅仅是当前文件系统fsys_entry::close_func的简单封装。

d,文件系统驱动

你可以在stage2/fsys_*.c找到各个文件系统驱动,当然你如果 对某个文件的结构熟悉,而grub中又没有相应的驱动,你可以安装b节中方法向grub中添加此文件系统的支持,比如NTFS,你只要实现mount(判断是否是你所支持的文件系统),dir(打开文件或者目录),read(读),close(关闭文件)功能就好。
发表于 2005-1-12 19:05:40 | 显示全部楼层
顶一个先,希望能够继续下去
 楼主| 发表于 2005-1-13 11:52:31 | 显示全部楼层

3 Stage2-Shell

大部分情况我们是通过一个menulist文件来控制grub,这样grub会分析此文件的内容,然后显示一个菜单让我们选择。但是我不打算介绍grub stage2时怎样显示这个菜单的,这不是grub特殊的地方,这一节将对菜单选择执行的底层机制做小小的分析。(在grub没有找到menulist的时候,他就会执行一个shell,你完全可以通过这里内置的命令来控制grub,实际上你可以把menulist当作一个脚本文件,它也完全是通过内置命令执行的)

a,stage2流程

stage1或者stage1-5加载完stage2后,会跳转至stage2执行,stage2的入口是stage2/asm.S
asm.S在设置好c运行环境之后,会调用第一个c函数init_bios_info(stage2/common.c),这个函数在执行一些底层的初始化之后,会调用stage2的main函数cmain(stage2/stage2.c),这样stage2这个 mini os正式开始运行了!

针对menu.lst和shell这两种情况,cmain将:
menu.lst: run_menu()(stage2.c)->run_script()(cmdline.c)->find_command->执行命令函数
shell: enter_cmdline()(cmdline.c)->find_command->执行命令函数

殊途同归,最后都归结为命令行的解释执行
find_command(stage2/cmdline.c)按照menu.lst中或者shell用户输入的命令字符串,在一个全局性struct builtin *builtin_table[](stage2/builtin.c)变量中去找到内置命令的函数,然后执行。

值得一提的是grub的shell类似bash的命令补全和命令历史纪录。



b,内部数据结构
struct builtin
{
  /* 命令名称,重要,是搜索命令时的依据  */
  char *name;
  /* 命令函数,重要,是搜索匹配后调用的函数  */
  int (*func) (char *, int);
  /* 功能标示,一般未用到.  */
  int flags;
  /* 简短帮助信息  */
  char *short_doc;
  /* 完整帮助信息 */
  char *long_doc;
};
struct builtin *builtin_table[];(stage2/builtin.c)



c,Hack 提示

编写一个自己的grub命令。只需按照b节所述,填充一个struct builtin结构,按后将其指针放入builtin_table指针数组,你就可以在menu.lst或者grub shell中使用这个命令了。
发表于 2005-1-13 12:02:35 | 显示全部楼层
顶,:thank
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表