LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: phyma

Grub 源代码分析

[复制链接]
发表于 2006-11-19 20:08:08 | 显示全部楼层
有一个问题:
      在stage2/start.S 中最后有一段变量的定义:
blocklist_default_len:
                        /* this is the number of sectors to read */
#ifdef STAGE1_5
        .word 0                /* the command "install" will fill this up */
#else
        .word (STAGE2_SIZE + 511) >> 9
#endif


    其中的STAGE2_SIZE明显应该在stage2_size.h中定义,因为在文件头部有:
#ifndef STAGE1_5
#include <stage2_size.h>
#endif

     但是我在grub-0.93下面没有找到stage2_size.h这个文件,按说它应该在stage2下面,谁知道它在什么地方吗?
回复 支持 反对

使用道具 举报

发表于 2006-11-26 19:43:40 | 显示全部楼层
困扰很久的问题
受到启发了!
回复 支持 反对

使用道具 举报

发表于 2007-1-19 22:34:44 | 显示全部楼层
stage2_size.h文件是在编译过程中,根据stage2映象的具体文件大小来设置的,具体可以
参看一下stage2目录下的Makefile.am文件中的脚本语句:
常量STAGE2_SIZE是在编译时根据stage2映象的具体大小自动生成的,具体可以参看
stage2/Makefile.am:
      set dummy `ls -l pre_stage2`;\
      echo "#define STAGE2_SIZE $6" > stage2_size.h

你可以实际试一下,执行以上两条脚本语句,确实可以得到stage2_size.h文件,且里面定义的是常量STAGE2_SIZE的大小。
回复 支持 反对

使用道具 举报

发表于 2007-1-25 11:32:49 | 显示全部楼层
Post by phyma
这个主题源自westroom兄的意见。

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

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

(自己看书的时候常常跳过前言,觉得很多书的前言绪论实在让人厌烦,等看到正文的时候已经头晕目眩了,所以写这么多的介绍性文字已经是我的极限了,权当作抛砖引玉的作用,后面会陆续写些详细的分析文章,大家有兴趣可以一起写写)


书中内容的重要性由顺序决定!我不看前言和目录十多年,就得出个这样的结论, 呵呵。
回复 支持 反对

使用道具 举报

发表于 2007-1-26 16:15:36 | 显示全部楼层
恩 恩 长知识了 谢谢啦

菜菜问下  在GRUB的选择菜单里选了一个内核后 启动有输出类似  grub.conf里的一段
kernel /vmlinuz-2.6.18-1.2798.fc6 root=/LABEL/ ........
.............................
initrd /initrd-2.6.48-1.2798.fc6.img
..............................

这段话是由grub源码里控制输出的么?可以修改的么?
查看了一下stage2的文件夹里,好像不是boot.c控制的? 谢谢各位了
回复 支持 反对

使用道具 举报

发表于 2007-1-26 18:04:37 | 显示全部楼层
“grub在设置好内核后,然后切换至实模式,具体跳向哪里取决于kernel header里面的一个字段”
    希望这个问题能够得到重视,大家讨论一下。1、grub怎样切换至实模式;2、哪条指令根据kernel header相应字段决定了跳向,譬如说对 linux 2.6.x  kernel来说,它的哪个kernel   header  字段。
    看大家讨论grub善后工作的比较少。希望大家能够就这个问题展开讨论。
回复 支持 反对

使用道具 举报

发表于 2007-2-5 23:53:38 | 显示全部楼层
那我不自量力说说Grub中实模式和保护模式的切换把。。。= =
其实Grub的实现方法很标准(也许有什么巧妙的地方我没看出来?=v=b)
才疏学浅。。。望各位前辈指教。。。
PS:因为本来是写给学校的同学看的。。。所以有些地方说的比较基础。。。= =

标题:Grub中实现实模式和保护模式切换部分的代码分析
作者:CNLAS
说明:都是些个人愚见。。。出错勿怪。。。还请各位大牛指出。。。= =
/*  */中为原文件的注释
/*= =*/中为我加的注释
源文件位于\stage2\asm.S 版本为grub-0.97
提示:对win32asm爱好者一点小提示,grub的asm部分编译是由gcc中的gas来完成的。。。gas采用的asm是延续UNIX的AT&T格式。。。不太了解的同学可以先google学习一下。。。XD


/*
*  These next two routines, "real_to_prot" and "prot_to_real" are structured
*  in a very specific way.  Be very careful when changing them.
*
*  NOTE:  Use of either one messes up %eax and %ebp.
*/
ENTRY(real_to_prot)
.code16
/*=在Grub这个保护模式过程中。。。只加载了GDT。。。没有设定IDT。。。所以这个保护模式要在关闭可屏蔽中断的情况下运行=*/
cli
/* load the GDT register */
/*=向gdtr寄存器中写入GDT=注1=*/
DATA32 ADDR32 lgdt gdtdesc
/* turn on protected mode */
/*=修改cr0中的pe位切换到保护模式,CR0_PE_ON在shared.h中定义为0x1。。。即将PE位置1=*/
movl %cr0, %eax
orl $CR0_PE_ON, %eax
movl %eax, %cr0
/* jump to relocation, flush prefetch queue, and reload %cs */
DATA32 ljmp $PROT_MODE_CSEG, $protcseg
/*
  *  The ".code32" directive only works in GAS, the GNU assembler!
  *  This gets out of "16-bit" mode.
  */
.code32
protcseg:
/* reload other segment registers */
/*=保护模式和实模式中段寄存器的作用是不同的。。。所以这里加载的是段选择子(descriptor)PROT_MODE_DSEG在shared.h中定义为0x10。。。即GDT中保护模式下数据段的选择子=*/
movw $PROT_MODE_DSEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* put the return address in a known safe location */
/*=保存返回地址。。。STACKOFF在shared.h中定义为(0x2000 - 0x10)=*/
movl (%esp), %eax
movl %eax, STACKOFF
/* get protected mode stack */
/*=建立保护模式下的栈。。。注2=*/
movl protstack, %eax
movl %eax, %esp
movl %eax, %ebp
/* get return address onto the right stack */
/*=返回地址入栈=*/
movl STACKOFF, %eax
movl %eax, (%esp)
/* zero %eax */
xorl %eax, %eax
/* return on the old (or initialized) stack! */
ret

ENTRY(prot_to_real)
/* just in case, set GDT */
lgdt gdtdesc
/* save the protected mode stack */
/*=保存保护模式下的栈以便下次进入时再次使用=*/
movl %esp, %eax
movl %eax, protstack
/* get the return address */
movl (%esp), %eax
movl %eax, STACKOFF
/* set up new stack */
movl $STACKOFF, %eax
movl %eax, %esp
movl %eax, %ebp
/* set up segment limits */
/*=装入GDT中实模式下数据段的选择子。。。PSEUDO_RM_DSEG是GDT中一个规范段描述符。。。具体意义后面细讲。。。注3=*/
movw $PSEUDO_RM_DSEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* this might be an extra step */
ljmp $PSEUDO_RM_CSEG, $tmpcseg /* jump to a 16 bit segment */
tmpcseg:
.code16
/* clear the PE bit of CR0 */
/*=修改cr0的pe位。。。返回实模式。。。CR0_PE_OFF在shared.h中定义为0xfffffffe。。。即将PE位置0=*/
movl %cr0, %eax
andl  $CR0_PE_OFF, %eax
movl %eax, %cr0
/* flush prefetch queue, reload %cs */
DATA32 ljmp $0, $realcseg
realcseg:
/* we are in real mode now
  * set up the real mode segment registers : DS, SS, ES
  */
/* zero %eax */
/*=这里才是真正将实模式下数据段装入段寄存器=*/
xorl %eax, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* restore interrupts */
/*=已经回到实模式了。。。置IF为1开启可屏蔽中断。。。中断响应交由中断向量表来控制=*/
sti
/* return on new stack! */
DATA32 ret
.code32



注1:

DATA32 ADDR32 lgdt gdtdesc

gdtdesc是在asm.S最后定义的GDT选择子。。。由lgdt命令读入。。。该命令将48位存储器操作数读入gdtr寄存器。。。高双字为段基地址。。。低字是以字节为单位的段界限

/* this is the GDT descriptor */
gdtdesc:
.word 0x27   /* limit */ /*=定义了5个表项。。。每项8位。。共40位。。。=*/
.long gdt   /* addr */   

gdt的定义就在gdtdesc的上方。。。而且源代码中还很友好的给出了GDT表项的结构图

/*
* This is the Global Descriptor Table
*
*  An entry, a "Segment Descriptor", looks like this:
*
* 31          24         19   16                 7           0
* ------------------------------------------------------------
* |             | |B| |A|       | |   |1|0|E|W|A|            |
* | BASE 31..24 |G|/|0|V| LIMIT |P|DPL|  TYPE   | BASE 23:16 |
* |             | |D| |L| 19..16| |   |1|1|C|R|A|            |
* ------------------------------------------------------------
* |                             |                            |
* |        BASE 15..0           |       LIMIT 15..0          |
* |                             |                            |
* ------------------------------------------------------------
*
*  Note the ordering of the data items is reversed from the above
*  description.
*/

.p2align 2 /* force 4-byte alignment */
gdt:

/*=GDT的0项。。。必须为空=*/
.word 0, 0
.byte 0, 0, 0, 0
  
/*=保护模式下代码段的描述符
由表项定义它是一个可执行可读非一致的有效的32位代码段。。。
基地址是00000000H。。。以4K字节为单位的段界限值是0FFFFFH
描述符特权级DPL=0
=*/
/* code segment */
.word 0xFFFF, 0
.byte 0, 0x9A, 0xCF, 0

/*=保护模式下数据段的描述符
由表项定义它是一个可读可写有效的32位数据段。。。
基地址是00000000H。。。以4K字节为单位的段界限值是0FFFFFH
描述符特权级DPL=0
=*/
/* data segment */
.word 0xFFFF, 0
.byte 0, 0x92, 0xCF, 0

/*=实模式下代码段的描述符
由表项定义它是一个可执行可读一致有效的16位代码段。。。
基地址是00000000H。。。以字节为单位的段界限值是0FFFFH
描述符特权级DPL=0
=*/
/* 16 bit real mode CS */
.word 0xFFFF, 0
.byte 0, 0x9E, 0, 0

/*=实模式下数据段的描述符
由表项定义它是一个可读可写有效的16位数据段。。。
基地址是00000000H。。。以字节为单位的段界限值是0FFFFH
描述符特权级DPL=0
=*/
/* 16 bit real mode DS */
.word 0xFFFF, 0
.byte 0, 0x92, 0, 0


注2:

movl protstack, %eax

1)protstact是在asm.S中定义个一个长整型。。。初始化值为PROTSTACKINIT

protstack:
        .long        PROTSTACKINIT

2)PROTSTACKINIT在shared.h中定义为(FSYS_BUF - 0x10)

#define PROTSTACKINIT   (FSYS_BUF - 0x10)

3)FSYS_BUF在shared.h中定义为

#define FSYS_BUF RAW_ADDR (0x68000)

4)RAW_ADDR在shared.h的最上面是这么定义的。。。

/* Maybe redirect memory requests through grub_scratch_mem. */
#ifdef GRUB_UTIL
extern char *grub_scratch_mem;
# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
# define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
#else
# define RAW_ADDR(x) (x)
# define RAW_SEG(x) (x)
#endif

注3:

为何要在切换会实模式之前把一个规范化描述符选择子装入那些段寄存器呢?
这涉及到80x86架构的CPU内部结构问题。。。
从80286开始每个段寄存器都配有一个高速缓冲寄存器。。。。这些寄存器对程序员是不可见的。。。。当给段寄存器装入选择子的时候,处理器自动从描述符表中将对应的描述符信息装入与段寄存器对应的高速缓冲寄存器中。。。以后访问该段时只要从这里读信息就行了。。。不必再去描述符表中查询。。。在保护模式下。。。可以通过将相应的选择子装入段寄存器来刷新这些高速缓冲器

在实模式中这些高速缓冲寄存器仍然发挥作用。。。实模式中段基址是段值*16。。。每个段的32位段界限都是固定的0FFFFH。。。而且很多属性都是固定的。。。实模式中不存在GDT没有办法设置这些高速缓冲寄存器中的属性。。。只能沿用保护模式下的值。。。所以在从保护模式返回实模式之前。。。一定要加载一个合适的描述符选择子到相关的段寄存器。。。从而使得这些高速缓冲寄存器满足实模式的要求


实力所限。。。只能分析到这种地步了。。。望达人修正补充。。。多谢~~~
回复 支持 反对

使用道具 举报

发表于 2007-3-16 09:10:40 | 显示全部楼层
好东西,慢慢学习!
回复 支持 反对

使用道具 举报

发表于 2007-4-20 15:25:42 | 显示全部楼层
讲得很好,
还有一个问题要请教,就是从GRUB这个OS进入真正的OS的过程,
不同的OS应该有不同的入口点,不同OS的IMAGE加载地址也是不一样的,请教GRUB中这个是怎么实现的?
回复 支持 反对

使用道具 举报

发表于 2007-4-26 12:45:29 | 显示全部楼层
太好了,顶.
希望谁可以整理下,便于下载学习
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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