当内核配置了内存盘时, 内核在初始化时能够将软盘加载到内存盘中作为根盘. 当同时配置了初始化内存盘(Initail RAM Disk)时, 内核在初始化时能够在安装主盘之前, 通过引导程式所加载的initrd文档建立一个内存初始化盘, 首先将他安装成根文档系统, 然后执行其根目录下的linuxrc 文档, 可用于在安装主盘之前加载一些内核模块. 等到linuxrc 程式退出后, 再将主盘安装成根文档系统, 并将内存初始化盘转移安装到其/initrd目录下。

当主盘就是initrd所生成的内存初始化盘时, 不再进行重新安装, 在DOS下用loadlin加载的抢救盘就是这种工作方式。

引导程式所加载的initrd为文档系统的映象文档, 能够是gzip压缩的, 也能够是不压缩的. 能够识别的文档系统有minix,ext2,romfs三种。

当内核的根盘为软盘时, 内核初始化时会测试软盘的指定部位是否存在文档系统或压缩文档映象, 然后将之加载或解压到内存盘中作为根盘. 这是单张抢救软盘的工作方式。

以下是有关代码:

   init/main.c

              #ifdef CONFIG_BLK_DEV_INITRD

              kdev_t real_root_dev; 启动参数所设定的根盘设备

              #endif

              asmlinkage void __init start_kernel(void)

              {

               char * command_line;

               unsigned long mempages;

               extern char saved_command_line[];

               lock_kernel();

               printk(linux_banner);

               setup_arch(&command_line); arch/i386/kernel/setup.c中,

            初始化initrd_start和initrd_end两个变量

               ...

              #ifdef CONFIG_BLK_DEV_INITRD

               if (initrd_start && !initrd_below_start_ok &&

               initrd_start < min_low_pfn << PAGE_SHIFT) {

               ; min_low_pfn为内核末端_end所开始的物理页号,initrd_start,initrd_end在rd.c中定义

               printk(KERN_CRIT "initrd overwritten (0xlx < 0xlx) - "

               "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);

               initrd_start = 0;

               }

              #endif

               ...

               kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); 创建init进程

               unlock_kernel();

               current->need_resched = 1;

               cpu_idle();

              }

              static int init(void * unused)

              {

               lock_kernel();

               do_basic_setup();

               /*

               * Ok, we have completed the initial bootup, and

               * we're essentially up and running. Get rid of the

               * initmem segments and start the user-mode stuff..

               */

               free_initmem();

               unlock_kernel();

               if (open("/dev/console", O_RDWR, 0) < 0)

               printk("Warning: unable to open an initial console.\n");

               (void) dup(0);

               (void) dup(0);

               /*

               * We try each of these until one succeeds.

               *

               * The Bourne shell can be used instead of init if we are

               * trying to recover a really broken machine.

               */

               if (execute_command)

               execve(execute_command,argv_init,envp_init);

               execve("/sbin/init",argv_init,envp_init);

               execve("/etc/init",argv_init,envp_init);

               execve("/bin/init",argv_init,envp_init);

               execve("/bin/sh",argv_init,envp_init);

               panic("No init found. Try passing init= option to kernel.");

              }

              static void __init do_basic_setup(void)

              {

              #ifdef CONFIG_BLK_DEV_INITRD

               int real_root_mountflags;

              #endif

               ...

              #ifdef CONFIG_BLK_DEV_INITRD

               real_root_dev = ROOT_DEV; ROOT_DEV为所请求根文档系统的块设备

               real_root_mountflags = root_mountflags;

               if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;

               else mount_initrd =0;

              #endif

               start_context_thread();

               do_initcalls(); 会调用partition_setup()中加载内存盘

               /* .. filesystems .. */

               filesystem_setup();

               /* Mount the root filesystem.. */

               mount_root();

               mount_devfs_fs ();

              #ifdef CONFIG_BLK_DEV_INITRD

               root_mountflags = real_root_mountflags;

               if (mount_initrd && ROOT_DEV != real_root_dev

               && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {

               ; 假如当前根盘为initrd所建立的内存盘

               int error;

               int i, pid;

               pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);

            创建新的任务去执行程式/linuxrc

               if (pid>0)

               while (pid != wait(&i)); 等待linuxrc进程退出

               if (MAJOR(real_root_dev) != RAMDISK_MAJOR

               || MINOR(real_root_dev) != 0) {

               ; 假如原来的根盘不是0号内存盘,则使用原来的根文档系统,

               ; 并且将内存盘转移到其/initrd目录下

               error = change_root(real_root_dev,"/initrd");

               if (error)

               printk(KERN_ERR "Change root to /initrd: "

               "error %d\n",error);

               }

               }

              #endif

              }

              #ifdef CONFIG_BLK_DEV_INITRD

              static int do_linuxrc(void * shell)

              {

               static char *argv[] = { "linuxrc", NULL, };

              

               close(0);close(1);close(2);

               setsid(); 配置新的session号

               (void) open("/dev/console",O_RDWR,0);

               (void) dup(0);

               (void) dup(0);

               return execve(shell, argv, envp_init);

              }

              #endif

              ; arch/i386/kernel/setup.c

              #define RAMDISK_IMAGE_START_MASK 0x07FF

              #define RAMDISK_PROMPT_FLAG 0x8000

              #define RAMDISK_LOAD_FLAG 0x4000

              #define PARAM ((unsigned char *)empty_zero_page)

              #define RAMDISK_FLAGS (*(unsigned short *) (PARAM 0x1F8)) 可用rdev配置的参数

              #define LOADER_TYPE (*(unsigned char *) (PARAM 0x210))

              #define INITRD_START (*(unsigned long *) (PARAM 0x218)) 初始化盘映象起始物理地址

              #define INITRD_SIZE (*(unsigned long *) (PARAM 0x21c)) 初始化盘字节数

              

              void __init setup_arch(char **cmdline_p)

              {

               ...

              #ifdef CONFIG_BLK_DEV_RAM

               rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; 以块为单位

               rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);

               rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);

              #endif

               ...

              #ifdef CONFIG_BLK_DEV_INITRD

               if (LOADER_TYPE && INITRD_START) {

               if (INITRD_START   INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {

               ; max_low_pfn表示内核空间1G范围以下最大允许的物理页号

               reserve_bootmem(INITRD_START, INITRD_SIZE);

               initrd_start =

               INITRD_START ? INITRD_START   PAGE_OFFSET : 0; 转变为内核逻辑地址

               initrd_end = initrd_start INITRD_SIZE;

               }

               else {

               printk("initrd extends beyond end of memory "

               "(0xlx > 0xlx)\ndisabling initrd\n",

               INITRD_START   INITRD_SIZE,

               max_low_pfn << PAGE_SHIFT);

               initrd_start = 0;

               }

               }

              #endif

               ...

              }

              ; fs/partitions/check.c:

              int __init partition_setup(void)

              {

               device_init(); 包含ramdisk设备的初始化

              #ifdef CONFIG_BLK_DEV_RAM

              #ifdef CONFIG_BLK_DEV_INITRD

               if (initrd_start && mount_initrd) initrd_load();

               ;假如启动时加载了initrd文档,则用他去初始化根内存盘

               else

              #endif

               rd_load(); 假如内核配置了内存盘并且根盘指定为软盘则试图将软盘加载为根内存盘

              #endif

               return 0;

              }

              

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!