grub和initrd

GRUB三种安装方式

1.install命令

命令格式:
install: install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]
STAGE1:指定stage1文件所在绝对路径。
DEVICE:指定vstage1装载的位置。
STAGGE2:指定stage2文件所在绝对路径。
ADDR:指定装载stage2的位置,如果不写,系统自动决定。
例如:
boot为独立分区时:
grub>root (hd0,0)
grub>install /grub/stage1 (hd0) /grub/stage2 p /grub/grub.conf
 
boot为非独立分区时:
grub>root (hd0,0)
grub>install (hd0,0)/boot/grub/stage1 (hd0) (hd0,0)/boot/grub/stage2 p (hd0,0)/boot/grub/grub.conf
该句可以写成如下这样:
grub>root (hd0,0)
grub>install /boot/grub/stage1 (hd0) /boot/grub/stage2 p /boot/grub/grub.conf
注意:
boot分区为独立分区与非独立分区时,安装方法有区别。

 2.setup命令

命令格式:
setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]
INSTALL_DEVICE:指定安装grub的位置。
IMAGE_DEVICE:指定要安装的镜象文件。
例如:
[root@RHEL5 ~]# grub
Probing devices to guess BIOS drives. This may take a long time.
    GNU GRUB  version 0.97  (640K lower / 3072K upper memory)
 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename.]
grub> root (hd0,)
 Possible partitions are:
   Partition num: 0,  Filesystem type is ext2fs, partition type 0x83
   Partition num: 1,  Filesystem type unknown, partition type 0x82
   Partition num: 2,  Filesystem type is ext2fs, partition type 0x83
grub> root (hd0,0)
 Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
 Checking if "/boot/grub/stage1" exists... no
 Checking if "/grub/stage1" exists... yes
 Checking if "/grub/stage2" exists... yes
 Checking if "/grub/e2fs_stage1_5" exists... yes
 Running "embed /grub/e2fs_stage1_5 (hd0)"...  15 sectors are embedded.
succeeded
 Running "install /grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/grub/stage2 /grub/grub.conf"... succeeded
Done.
grub>

 3.grub-install命令

grub-install拷贝grub镜象文件到DIR/boot目录中(可以通过参数--root-directory指定目录),并用grub shell安装grub到MBR中。
命令格式:
grub-install [OPTION] install_device
例如:
[root@RHEL5 ~]# grub-install hd0
Installation finished. No error reported.
This is the contents of the device map /boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.
# this device map was generated by anaconda
(hd0)     /dev/sda
[root@RHEL5 ~]#

 4.区别

这3种方式中,最常用的是grub-install,其中install是最底层的方式。setup是更高一层的方式,而grub-install是最高级最简单的方式。grub-install命令安装grub到MBR中的时候利用的安装源是/usr/share/grub/i386-redhat/下的stage1、stage2和各种stage1_5。而install命令与setup命令安装grub的安装源是/boot/grub目录中的stage1、stage2和各种stage1_5。所以要使用这两种安装方法来安装grub到MBR中的时候,确保/boot/grub目录中的stage1、stage2和各种stage1_5必须存在。同时grub-install命令安装的grub只是利用stage1_5 -> stage2 方式的文件系统方式去查找,如果stage2不存在,那么系统就不能启动。setup命令安装的grub是stage1_5 -> stage2 方式去查找stage2,首先监测是否是合适的文件系统的驱动,如果存在就使用文件系统逻辑的方式查找stage2 ;如果找不到就用blocklist的方式再找stage2。install命令安装的grub使用stage1 -> stage2方式去查找
 
 
 
 
 
 
 
这里介绍一种比较少见的情况。有时我们会遇到主机不带显示器/键盘,但由于某些原因需要重启主机并访问 GRUB,

这时怎么办?你可能会说用串口连接。不错,通过串口的确可以控制 GRUB ,但有一个问题,即使你把笔记本连接到该主机上,

但启动时 GRUB 并不会自动使用笔记本的键盘,又如何通过笔记本控制GRUB 呢?

GRUB 支持一个功能叫做 preset menu(预设菜单),工作原理 :

a)GRUB 检查是否启用了 preset menu 功能,如果是的话,加载 preset menu 文件(不是 grub.conf)

b)GRUB 加载 grub.conf ,这个过程是一定会执行的,不管有没有 preset menu 存在。

c)在 grub.conf 被加载后,不管 grub.conf 有没有引导项目,只要 preset menu 含有任何引导条目,都会被清掉。只有 grub.conf 

    文件不可用时,preset menu 的内容才会被保留。

看到这里,我想你应该明白 preset menu 怎么用了。我们可以定义一个文件 pre-menu.conf ,内容是把显示切换到 COM1 上 ,grub.conf 则是正常的内容。

然后把笔记本接到故障主机的 COM1,启动超级终端。再启动故障主机,GRUB 会先把显示切换到 COM1 ,然后加载 grub.conf ,后面的过程就和普通情况没

有什么不同。

  1. 要使用 preset-menu ,你必须在执行 configure 脚本时指定 –-preset-menu ,例如
  2. #./configure –-preset-menu=pre-menu.conf
  3. # make
  4. # make install
  5. pre-menu.conf 文件的内容就是下面两句 :
  6. serial –-unit=0 –-speed=9600
  7. terminal –-timeout=0 serial
复制代码


注意,当内核开始执行时,显示也就交回给原来的主机,而不再是你的笔记本了。要解决该问题,

可以在显示菜单是进入命令模式,在 kernel 行后面加上  console=ttyS0,这样 boot 时就可以在超级终端上看到启动的信息了。

不过在 login 提示符出现时,显示输出又会回到原来的故障主机上了。这时你可以用 secureCRT 来登录了,不需要再用到超级终端了。

整体效果如下图 :(通过串口看的)

 

选择引导 Red Hat 9 项目 :



一旦你不想使用preset-menu了,是否直接删除 pre-menu.conf 就可以呢?

不可以。因为 pre-menu.conf 已经被嵌入到 grub 中了,这时留在硬盘上的 pre-menu.conf 文件其实已经没有用了。要象取消 preset-menu 功能,

必须重新 congfiure ,并去掉 –-enable-preset-menu 选项,再重新安装 GRUB 
 
 
 
 
1. 安装grub  
我用的grub是Redhat8.0带的grub安装包: grub-0.92-7.rpm  
安装: rpm -ivh grub-0.92-7.rpm  
其他安装方式也一样,只要你安装上grub就行了.RH8缺省用的grub, 1,2步骤可以省了.  
2. 建立grub的环境  
cp /usr/share/grub/i386-pc/* /boot/grub  
3. 生成grub的配置文件/boot/grub/menu.conf  
按照上面所讲的grub.conf来生成一个配置文件.  
注意了, 这里我的linux在/dev/hda4,所以menu.conf那些分区位置为(hd0,3),  
你的可能不一样了,不能完全照着"画瓢"噢! 下面第3步install的中的分区位置也应该和你的系统一致.  
3. 安装grub至Linux分区boot  
将grub的stage1安装到/dev/hda4的boot扇区(hd0,3). 过程如下:  
/sbin/grub (运行grub)  
grub>; install (hd0,3)/boot/grub/stage1 d (hd0,3) (hd0,3)/boot/grub/stage2 p (hd0,3)/boot/grub/menu.conf  
(注意,上面"grub>;"为grub的提示符,其后内容写在一行上.)  
4. 取得grub的boot信息  
过程如下:  
dd if=/dev/hda4 of=/grub.lnx bs=512 count=1  
这样得到grub的引导信息,只要用NT Loader来加载它就行了.  
5. 将上面得到的grub.lnx弄到Windows的C盘根目录下  
可以先把grub.lnx弄得软盘上,然后启动windows,拷贝到C:\; 情况允许也可以直接在Linux下拷贝到C:了. 我的C盘(即设备/dev/hda1)为FAT32, 可以直接从Linux下弄过去了. 如下:  
mount -t vfat /dev/hda1 /mnt/c  
cp /grub.lnx /mnt/c  
umount /mnt/c  
6. 修改NT Loader的boot.ini  
在其中加入一行: C:\grub.lnx="Redhat Linux - GRUB"  
加入后boot.ini的内容如下:  
[boot loader]  
timeout=15  
default=C:\boot.lnx  
[operating systems]  
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect  
[VGA mode]" /basevideo /sos  
C:\grub.lnx="Redhat Linux - GRUB"  
OK. 可以用NT Loader加载Linux了, 其实上面过程基本上和用NT Loader加载LILO一样.其基本思想就是用NT Loader来加载LILO或grub的引导区(grub.lnx), 其中的关键就是LILO或grub的引导区的获取.
 
 
 
 

Initrd的作用有三:

1.提高系统的可移植性
把更多的内核功能条目编译成模块,不仅仅是为了减小内核体积,更重要的是面对各种不同的硬件架构,可以使用initrd中的linuxrc按需进行模块加载以驱动硬件,甚至对于CPU类型或者多处理机也可以进行手工选择内核(配合syslinux这类boot loader)

2.LIVECD(光盘上的Linux)必备的部件
现在的可启动光盘都沿用1995年制定的El Torito标准,它的启动原理在于模拟软盘启动映像,这个映像的大小一般被限制在2800KB,也就是两张软盘的大小,它包含了syslinux(也可以用isolinux,它对映像的大小要求更宽松),syslinux的配置文件,initrd.img以及内核。这时候内核的大小就必须要有约束了(当然,也有来自1MB实模式内存空间的约束),把更多的模块压缩进initrd.img中去,可以缩小启动映像的体积。
最重要的是,linuxrc脚本对于硬盘,光驱模块的加载至关重要,因为livecd要适应尽量多的硬件架构,所以它必须能按需加载模块,这时候 initrd就派上用场了。比如说,我们在vmware里运行knoppix,knoppix的linuxrc就自动加载BusLogic.o模块(通过轮换insmod来实现)。

3.在linuxrc脚本中可以很方便地启用个性化bootsplash
给出initrd的原理图例(请参看附件)以及相关源码分析:
/*init/do_mounts.c中的prepare_namespace函数 -- 确定系统的根文件系统*/

void __init prepare_namespace(void)
{
int is_floppy;

mount_devfs();

md_run_setup();

if (saved_root_name[0]) {
root_device_name = saved_root_name;
ROOT_DEV = name_to_dev_t(root_device_name);
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;
}

is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
/*[2]尝试处理initrd,见下*/
if (initrd_load())
goto out;
/*initrd_load()返回0,没有处理initrd,存在以下两种可能*/
/*或许已加载initrd但由于根设备是ramdisk而没有进行initrd处理,
则rd_doload==1, 调用rd_load_disk使用/dev/root取代上次rd_load_image中的/dev/root.old,ROOT_DEV=Root_RAM0*/
/*或许是没有initrd以致,则rd_doload==0,ROOT_DEV!=Root_RAM0*/
/*rd_doload由arch/i386/kernel/setup.c中的setup_arch函数根据boot loader的命令行参数来决定*/

if (is_floppy && rd_doload && rd_load_disk(0))
ROOT_DEV = Root_RAM0;
/*根据ROOT_DEV挂载文件系统*/
/*注意橙红色标示的两个mount_root()*/
mount_root();
/*无论有无经过initrd处理,最终为内核作最后chroot处理,确定系统的最终根文件系统*/

out:
umount_devfs("/dev");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
security_sb_post_mountroot();
mount_devfs_fs ();
}

 
 
 
 
它的作用是在没有mount /分区以前,系统要执行一些操作,比如挂载scsi驱动,它就把initrd释放到内存里,作一个虚拟的/,然后执行其根目录下的一个脚本
“linuxrc”,运行insmod和nash命令挂装模块。为什么有的时候我们在lilo或grub的配置文件中不加入该行都可以正常开机呢?这是因
为我们一般的PC机都没有使用scsi硬盘等需要先加载其驱动的设备,所以就算没有initrd***.img也可以正常开机。但是如果我们要在服务器上
为其编译新内核那就一定不要忘记也为其新建一个initrd文件呀!
好,下面来看看如何查看initrd***.img里面的内容和如何为你的新内核创建一个新的initrd.img文件。
查看initrd.img:
initrd***.img虽然后缀是“img”,但其实它是一个gz格式的文件,我们可以先把它解压,然后载挂装到目录下:
1、cp initrd.img initrd.gz
2、guzip initrd.gz
3、mount -o loop initrd /mnt/floppy
进入/mnt/floppy目录,我们就可以看到initrd***.img文件的庐山真面目了。
制作initrd文件
当我们编译了一个新的内核,也不要忘了为我们的scsi设备做一个新的initrd镜像:
语法:
mkinitrd 文件名 内核的目录名
示例:
mkinitrd initrd-2.4.19.img 2.4.19
initrd-2.4.19.img文件是自己任意取的,但最好对应自己的内核版本号。
2.4.19是在/lib/modules中的目录名,对应内核的版本。
当然,我们也可以在挂装了initrd***.img文件后直接添加模块到/lib目录中,然后修改linuxrc脚本让其开机进行挂装。但必须具备一定的shell脚本的能力才行
 
 
 
 
 

驱动包重新生成了并不意味着Linux就可以识别网卡了,因为Linux必须依靠一种逻辑,将硬件设备和驱动模块文件对应起来。这个逻辑就被定义在modules目录下的除modules.cgz之外的文件中:


命令输出 3. 设备驱动识别信息文件
                [root@ericvm modules]# lsmodule-info  modules.cgz  modules.dep  modules.pcimap  modules.usbmap  pci.ids  pcitable

如上所示,pcitable, modules.pcimap中定义了PCI设备和驱动模块之间的对应关系,modules.dep中定义了模块和模块之间的依赖关系(比如,各种SCSI设备都会依赖一个基础的SCSI驱动模块),module-info中定义了驱动的静态描述信息......

要填写这些文本文件,也很简单,首先我们必须要知道这块e1000网卡的PCI设备信息,由于在服务器上e1000这块网卡已经安装完成了,所以我们可以在服务器上取到我们想要的信息:


命令输出 4. 查看网卡硬件信息
                [root@ericvm ~]# lspci............  ignore some outputs04:00.0 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper04:00.1 Ethernet controller: Intel Corporation Enterprise Southbridge DPT LAN Copper............  ignore some outputs

lspci列出了服务器上两块网卡的设备信息,根据网卡设备的ID号码(04:00.0, 04:00.1),我们就可以在lspci –n的输出中找到设备的vendor code和device code(请参考lspci的manual了解lspci):


命令输出 5. 查看网卡code
                [root@ericvm ~]# lspci –n............  ignore some outputs04:00.0 Class 0200: 8086:1096 (rev 01)04:00.1 Class 0200: 8086:1096 (rev 01)............  ignore some outputs

在lspci –n的输出中,我们找到了两块网卡的vendor code和device code – 8086和1096。得到了vendor code和device code之后,就可以更新initrd.img中modules目录下的pcitable, modules.pcimap等这些文件了。举例来说,在pcitable中查找e1000,能发现很多设备和e1000这个驱动关联,但是唯独没有8086:1096的组合,这就是为什么Linux无法驱动这块e1000网卡的原因了,我们需要手动将8086, 1096这两个code加入到pcitable中,并将这个设备对应到e1000驱动上。照此方法,更新其余的文件,如module-info, modules.pcimap等。

 

 

 

 

 

篇文章(什么是 initrd.img) 提到 initrd.img有两种。一种是2.4版本内核以及之前的内核使用的,从2.5开始是另外一种initrd.img。2.6版的initrd.img的解压方式上文已经介绍了。2.4版本使用的initrd.img也需要先用zip方式解压得到 initrd文件,不过之后就不是cpio再进行解压了。这里获得到的initrd文件已经是个标准的image文件了(这个文件我们称为image-initrd),在linux下需要进行挂在,然后可以直接访问。这两种格式的initrd不只是打包方式不同,内部文件也有不同。下面介绍下2种文件的区别。

image-initrd

(1) boot loader(一般大家常用的是grub,关于它的介绍可以到网上搜索)把 initrd.img 初始化成一个设备 /dev/intrd。接着boot loader 把内核以及/dev/initrd的内容加载到内存。
(2) 在内核初始化过程中,内核把 /dev/initrd 设备的内容解压缩并拷贝到 /dev/ram0 设备上。
(3) 内核以可读写的方式把 /dev/ram0 设备挂载为原始的根文件系统。
(4) 如果 /dev/ram0 被指定为真正的根文件系统,那么内核不会执行(5)、(6)、(7)的操作,因为这下操作是为了帮内核加载最终的根文件系统做的工作。
(5) 执行 initrd 上的 /linuxrc 文件,linuxrc 通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。
(6) /linuxrc 执行完毕,真正的根文件系统被挂载。
(7) 如果真正的根文件系统存在 /initrd 目录,那么 /dev/ram0 将从 / 移动到 /initrd。否则如果 /initrd 目录不存在, /dev/ram0 将被卸载。
(8) 在真正的根文件系统上进行正常启动过程 ,执行 /sbin/init。

linux2.4内核的 initrd 的执行是作为内核启动的一个中间阶段,也就是说 initrd 的 /linuxrc执行以后,内核会继续执行初始化代码。2.6 内核同时支持 image-initrd 和 cpip-initrd。而且 image-initrd处理流程也是这样的。

cpio-initrd

(1) boot loader 把内核以及 initrd 文件加载到内存的特定位置
(2) 内核判断initrd的文件格式,如果是cpio格式。
(3) 将initrd的内容释放到/rootfs中。(rootfs本身也是一个基于内存的文件系统。这样就省掉了ramdisk的挂载、卸载等)
(4) 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给/init文件处理。也就是其实到了最后一步,内核就已经完成了自己所有的工作,直接移交给initrd 的/init。

 

 

 

 

2. initramfs (via a cpio archive)

这种方式仅仅需要把一个符合linux标准的root文件系统所在目录中的文件加到一个cpio档里头,然后“打包”即可。

首先,参考资料[8,9]创建一个文件系统。

$ cd /tmp/initrd/cpio
在这个目录下创建一个符合linux标准的root文件系统
$ .... do what you should to do ...



之后是把这个目录下的内容加到一个cpio档里头。

$ find . | cpio -c -o > ../ramdisk
$ file ../ramdisk 
../ramdisk: ASCII cpio archive (pre-SVR4 or odc)



"打包"(压缩)一下。

$ sync
$ cd ../
$ gzip -9 ramdisk
$ file ramdisk.gz 
ramdisk.gz: gzip compressed data, was "ramdisk", from Unix, last modified: Sat Apr 19 17:37:25 2008, max compression



到这里,这个ramdisk.gz在2.6的内核之后也应该可以类似上面的一样使用了,不过别忘记了加上相应的内核选项,比如(initramfs)初始化文件系统支持。



如下挂载虚拟映像文件:
m ount镜像文件的分区到Domine-0的某个目录(如/mnt)
mount -o loop,offset=$((10474380*512)) /virtualmachine/vm243/disk0 /mnt
注意offset的起始位置。
 

解压cpio文件

  cpio -idmv < filename.cpio

编辑本段解压img文件

  cpio -idmv < filename.img

编辑本段cpio 备份还原

  备份:cpio -covB > [file|device] 将数据备份到文件或设备上
  还原:cpio -icduv < [file|device} 将数据还原到系统中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值