Linux启动分析之Initramfs

在前面已经分析了rootfs的挂载,解决了VFS架构下原始挂载点的问题,也提到了Initramfs文件包的填充,这里记下如何实现Initramfs填充

一、Initramfs概述

1.initrd

    在早期的linux系统中,一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。

   为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块,可执行文件和启动脚本。当系统启动的时候,bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,然后执行根目录中的/linuxrc脚本(cpio格式的initrd为/init,而image格式的initrd<也称老式块设备的initrd或传统的文件镜像格式的initrd>为/initrc),您就可以在这个脚本中加载realfs(真实文件系统)存放设备的驱动程序以及在/dev目录下建立必要的设备节点。这样,就可以mount真正的根目录,并切换到这个根目录中来。

2.Initramfs

   在linux2.5中出现了initramfs,它的作用和initrd类似,只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上,其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。

二、Initramfs加载

kernel/init/main.c

static noinline void __init_refok rest_init(void)
{
  ......
  kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);  //内核线程0
  ......
  pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);  //内核线程
  ......
  init_idle_bootup_task(current);
  ......
  schedule();  //kernel/kernel/sched.c 进程调度
  ......
}

由内核进程0创建的内核线程装载可执行程序init,成为一个普通进程——1号进程

static int __init kernel_init(void * unused)
{
  ......
  do_basic_setup();  //初始化设备驱动,加载静态内核模块;释放ramdisk到rootfs
  ......
  if (!ramdisk_execute_command)  ramdisk_execute_command = "/init";
  if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
    ramdisk_execute_command = NULL;
    prepare_namespace(); //加载磁盘文件系统;也即磁盘的文件系统挂载至rootfs的/root目录,并重新设备系统根文件系统和根目录
  }
  init_post(); //启动init进程
  ......
}

内核静态模块加载、驱动加载等

static void __init do_basic_setup(void)
{
  cpuset_init_smp();
  usermodehelper_init();
  init_tmpfs();
  driver_init();  //设备驱动初始化 kernel/drivers/base/init.c
  init_irq_proc();
  do_ctors();
  do_initcalls();  //加载内核模块
}
static void __init do_initcalls(void)
{
  ......
  for (fn = __early_initcall_end; fn < __initcall_end; fn++)
    do_one_initcall(*fn);
  ......
}

在do_initcalls中,是否支持ramdisk取决与kernel/init/Makefile;以下是释放ramdisk至rootfs:

kernel/init/initramfs.c

rootfs_initcall(populate_rootfs);
static int __init populate_rootfs(void)
{
  char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);  //解压Initramfs
  ......
  if (initrd_start) {  //uboot将启动ramdisk文件系统拷贝到了initrd_start处
    ......
    err = unpack_to_rootfs((char *)initrd_start,
			initrd_end - initrd_start);
    ......
    fd = sys_open((const char __user __force *) "/initrd.image",
			      O_WRONLY|O_CREAT, 0700);
    if (fd >= 0) {
      sys_write(fd, (char *)initrd_start,
					initrd_end - initrd_start);
      sys_close(fd);
      free_initrd();
    }
    ......
  }
  return 0;
}

init进程启动

kernel/init/main.c

static noinline int init_post(void)
{
  ......
  if (ramdisk_execute_command) {          //判断initramfs是否有init可执行文件
    (void) sys_dup(0);
    run_init_process(ramdisk_execute_command); //运行initramfs的init
    printk(KERN_WARNING "Failed to execute %s\n",
                                ramdisk_execute_command);
  } 
  ......
}
static void run_init_process(const char *init_filename)
{
  argv_init[0] = init_filename;
  kernel_execve(init_filename, argv_init, envp_init);    //内核空间调用用户空间函数kernel_execve
}

三、Initramfs实现
使用initramfs的内核配置(使用initramfs做根文件系统):
------------------------------------------------------
General setup  --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/rootfs_dir) Initramfs source file(s)   //输入根文件系统的所在目录,就和平时用的文件系统一样就可,用busybox生成的 

这样把initramfs编译到内核中,会导致最后生成的uImage会比平时大许多,所以得修改uboot的读取参数,不然uboot会出现校验失败

uboot/include/configs/mx6q_sabresd.h

#define CONFIG_EXTRA_ENV_SETTINGS                   \
        "mmc read ${loadaddr} 0x800 0x5800; bootm\0"    \   //把0x5800换成uImage的大小                                                                                                  
        "bootcmd=run bootcmd_mmc\0"   

启动log:

U-Boot 2009.08 (Dec 20 2016 - 11:10:25)


CPU: Freescale i.MX6 family TO1.5 at 792 MHz
Thermal sensor with ratio = 183
Temperature:   29 C, calibration data 0x5884df7d
mx6q pll1: 792MHz
mx6q pll2: 528MHz
mx6q pll3: 480MHz
mx6q pll8: 50MHz
ipg clock     : 66000000Hz
ipg per clock : 66000000Hz
uart clock    : 80000000Hz
cspi clock    : 60000000Hz
ahb clock     : 132000000Hz
axi clock   : 264000000Hz
emi_slow clock: 132000000Hz
ddr clock     : 528000000Hz
usdhc1 clock  : 198000000Hz
usdhc2 clock  : 198000000Hz
usdhc3 clock  : 198000000Hz
usdhc4 clock  : 198000000Hz
nfc clock     : 24000000Hz
Board: i.MX6Q-SABRESD: unknown-board Board: 0x63015 [WDOG ]
Boot Device: MMC
I2C:   ready
DRAM:   1 GB
MMC:   FSL_USDHC: 0,FSL_USDHC: 1,FSL_USDHC: 2,FSL_USDHC: 3
*** Warning - bad CRC or MMC, using default environment


In:    serial
Out:   serial
Err:   serial
i2c: I2C3 SDA is low, start i2c recovery...
I2C3 Recovery failed, I2C1 SDA still low!!!
Net:   got MAC address from IIM: 00:00:00:00:00:00
FEC0 [PRIME]
Hit any key to stop autoboot:  0 
mmc3(part 0) is current device


MMC read: dev # 3, block # 2048, count 22528 ... 22528 blocks read: OK
## Booting kernel from Legacy Image at 10800000 ...
   Image Name:   Linux-3.0.35-2666-gbdde708-g1a19
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    5621116 Bytes =  5.4 MB
   Load Address: 10008000
   Entry Point:  10008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK


Starting kernel ...


Uncompressing Linux... done, booting the kernel.
[    0.000000] Linux version 3.0.35-2666-gbdde708-g1a194ba-dirty (robin@Grandtelco) (gcc version 4.6.2 20110630 (prerelease) (Freescale MAD -- Linaro 2011.07 -- Built6
[    0.000000] CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c53c7d
[    0.000000] CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine: Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board
[    0.000000] Ignoring unrecognised tag 0x54410008
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.000000] CPU identified as i.MX6Q, unknown revision
[    0.000000] PERCPU: Embedded 7 pages/cpu @8c008000 s4928 r8192 d15552 u32768
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 194560
[    0.000000] Kernel command line: console=ttymxc0,115200 rdinit=/init ip=dhcp root=/dev/mmcblk0p1 rootwait
[    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Memory: 512MB 256MB = 768MB total
[    0.000000] Memory: 761096k/761096k available, 287480k reserved, 0K highmem
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     DMA     : 0xf4600000 - 0xffe00000   ( 184 MB)
[    0.000000]     vmalloc : 0xc0800000 - 0xf2000000   ( 792 MB)
[    0.000000]     lowmem  : 0x80000000 - 0xc0000000   (1024 MB)
[    0.000000]     pkmap   : 0x7fe00000 - 0x80000000   (   2 MB)
[    0.000000]     modules : 0x7f000000 - 0x7fe00000   (  14 MB)
[    0.000000]       .init : 0x80008000 - 0x80789000   (7684 kB)
[    0.000000]       .text : 0x80789000 - 0x80f4bc6c   (7948 kB)
[    0.000000]       .data : 0x80f4c000 - 0x80f8ca20   ( 259 kB)
[    0.000000]        .bss : 0x80f8ca44 - 0x80fd01c0   ( 270 kB)
[    0.000000] SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000] NR_IRQS:624
[    0.000000] MXC GPIO hardware
[    0.000000] sched_clock: 32 bits at 3000kHz, resolution 333ns, wraps every 1431655ms
[    0.000000] arm_max_freq=1GHz
[    0.000000] MXC_Early serial console at MMIO 0x2020000 (options '115200')
[    0.000000] bootconsole [ttymxc0] enabled
[    0.000000] Console: colour dummy device 80x30
[    0.224901] Calibrating delay loop... 1581.05 BogoMIPS (lpj=7905280)
[    0.313230] pid_max: default: 32768 minimum: 301
[    0.318163] Mount-cache hash table entries: 512
[    0.323437] CPU: Testing write buffer coherency: ok
[    0.328591] hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
[    0.429107] CPU1: Booted secondary processor
[    0.509115] CPU2: Booted secondary processor
[    0.589117] CPU3: Booted secondary processor
[    0.628627] Brought up 4 CPUs
[    0.644453] SMP: Total of 4 processors activated (6324.22 BogoMIPS).
[    0.668056] print_constraints: dummy: 
[    0.675312] print_constraints: vddpu: 725 <--> 1300 mV at 700 mV fast normal 
[    0.682754] print_constraints: vddcore: 725 <--> 1300 mV at 1150 mV fast normal 
[    0.690473] print_constraints: vddsoc: 725 <--> 1300 mV at 1200 mV fast normal 
[    0.698097] print_constraints: vdd2p5: 2000 <--> 2775 mV at 2400 mV fast normal 
[    0.705815] print_constraints: vdd1p1: 800 <--> 1400 mV at 1100 mV fast normal 
[    0.713443] print_constraints: vdd3p0: 2625 <--> 3400 mV at 3000 mV fast normal 
[    0.738582] No AHCI save PWR: PDDQ disabled
[    0.768496] hw-breakpoint: found 6 breakpoint and 1 watchpoint registers.
[    0.775329] hw-breakpoint: 1 breakpoint(s) reserved for watchpoint single-step.
[    0.782685] hw-breakpoint: maximum watchpoint size is 4 bytes.
[    0.788577] L310 cache controller enabled
[    0.792610] l2x0: 16 ways, CACHE_ID 0x410000c7, AUX_CTRL 0x02070000, Cache size: 1048576 B
[    0.812161] bio: create slab  at 0
[    0.818995] mxs-dma mxs-dma-apbh: initialized
[    0.823647] print_constraints: vmmc: 3300 mV 
[    0.829207] SCSI subsystem initialized
[    0.848664] imx-ipuv3 imx-ipuv3.0: IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)
[    0.868661] imx-ipuv3 imx-ipuv3.1: IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)
[    0.876494] mxc_mipi_csi2 mxc_mipi_csi2: i.MX MIPI CSI2 driver probed
[    0.882977] mxc_mipi_csi2 mxc_mipi_csi2: i.MX MIPI CSI2 dphy version is 0x3130302a
[    0.890708] MIPI CSI2 driver module loaded
[    0.894839] Switching to clocksource mxc_timer1
[    0.948280] PMU: registered new PMU device of type 0
[    0.953410] Static Power Management for Freescale i.MX6
[    0.958653] wait mode is enabled for i.MX6
[    0.962947] cpaddr = c0880000 suspend_iram_base=c0914000
[    0.968360] PM driver module loaded
[    0.972064] IMX usb wakeup probe
[    1.000189] JFFS2 version 2.2. (NAND) �© 2001-2006 Red Hat, Inc.
[    1.006911] msgmni has been set to 1486
[    1.012487] alg: No test for stdrng (krng)
[    1.016762] io scheduler noop registered
[    1.020723] io scheduler deadline registered
[    1.025092] io scheduler cfq registered (default)
[    1.030536] mxc_mipi_dsi mxc_mipi_dsi: i.MX MIPI DSI driver probed
[    1.036866] MIPI DSI driver module loaded
[    1.041102] mxc_sdc_fb mxc_sdc_fb.0: register mxc display driver ldb
[    1.047498] _regulator_get: get() with no identifier
[    1.079520] imx-ipuv3 imx-ipuv3.0: IPU DMFC DP HIGH RESOLUTION: 1(0,1), 5B(2~5), 5F(6,7)
[    1.133846] Console: switching to colour frame buffer device 128x37
[    1.171846] mxc_sdc_fb mxc_sdc_fb.1: register mxc display driver ldb
[    1.183836] mxc_sdc_fb mxc_sdc_fb.2: register mxc display driver lcd
[    1.190251] mxc_sdc_fb mxc_sdc_fb.2: ipu0-di0 already in use
[    1.195937] mxc_sdc_fb: probe of mxc_sdc_fb.2 failed with error -16
[    1.202256] mxc_sdc_fb mxc_sdc_fb.3: register mxc display driver ldb
[    1.208673] mxc_sdc_fb mxc_sdc_fb.3: ipu0-di1 already in use
[    1.214371] mxc_sdc_fb: probe of mxc_sdc_fb.3 failed with error -16
[    1.221403] imx-sdma imx-sdma: loaded firmware 1.1
[    1.230668] imx-sdma imx-sdma: initialized
[    1.368964] Serial: IMX driver
[    1.372179] imx-uart.2: ttymxc2 at MMIO 0x21ec000 (irq = 60) is a IMX
[    1.379036] imx-uart.0: ttymxc0 at MMIO 0x2020000 (irq = 58) is a IMX
[    1.385540] console [ttymxc0] enabled, bootconsole disabled
[    1.385540] console [ttymxc0] enabled, bootconsole disabled
[    1.400637] GPMI NAND driver registered. (IMX)
[    1.406120] snvs_rtc snvs_rtc.0: rtc core: registered snvs_rtc as rtc0
[    1.412799] i2c /dev entries driver
[    1.417082] Linux video capture interface: v2.00
[    1.620091] TCH2825 probe
[    1.623150] mxc_v4l2_output mxc_v4l2_output.0: V4L2 device registered as video16
[    1.630840] mxc_v4l2_output mxc_v4l2_output.0: V4L2 device registered as video17
[    1.638468] mxc_v4l2_output mxc_v4l2_output.0: V4L2 device registered as video18
[    1.646370] imx2-wdt imx2-wdt.0: IMX2+ Watchdog Timer enabled. timeout=60s (nowayout=1)
[    1.654641] sdhci: Secure Digital Host Controller Interface driver
[    1.660842] sdhci: Copyright(c) Pierre Ossman
[    1.665535] mmc0: SDHCI controller on platform [sdhci-esdhc-imx.3] using DMA
[    1.672659] sdhci sdhci-esdhc-imx.1: no card-detect pin available!
[    1.684683] mmc1: SDHCI controller on platform [sdhci-esdhc-imx.1] using DMA
[    1.691800] sdhci sdhci-esdhc-imx.2: no write-protect pin available!
[    1.708310] mmc2: SDHCI controller on platform [sdhci-esdhc-imx.2] using DMA
[    1.715621] mxc_vdoa mxc_vdoa: i.MX Video Data Order Adapter(VDOA) driver probed
[    1.729799] VPU initialized
[    1.737679] mxc_asrc registered
[    1.741041] Galcore version 4.6.9.6622
[    1.773390] Thermal calibration data is 0x5884df7d
[    1.778187] Thermal sensor with ratio = 183
[    1.799459] Anatop Thermal registered as thermal_zone0
[    1.804801] anatop_thermal_probe: default cooling device is cpufreq!
[    1.812486] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
[    1.827631] Bus freq driver module loaded
[    1.831660] Bus freq driver Enabled
[    1.834609] mmc0: new high speed DDR MMC card at address 0001
[    1.835091] mmcblk0: mmc0:0001 M32508 7.28 GiB 
[    1.835301] mmcblk0boot0: mmc0:0001 M32508 partition 1 4.00 MiB
[    1.835512] mmcblk0boot1: mmc0:0001 M32508 partition 2 4.00 MiB
[    1.836631]  mmcblk0: p1
[    1.859854] mxc_dvfs_core_probe
[    1.862208]  mmcblk0boot1: unknown partition table
[    1.867978] DVFS driver module loaded
[    1.870077]  mmcblk0boot0: unknown partition table
[    1.877974] snvs_rtc snvs_rtc.0: setting system clock to 1970-01-06 20:05:48 UTC (504348)
[    1.888226] Freeing init memory: 7684K
starting pid 1073, tty '': '/etc/init.d/rcS'
mount: mounting none on /dev/pts failed: No such file or directory
mount: mounting tmpfs on /dev/shm failed: No such file or directory


Please press Enter to activate this console. [    2.415952] mmc2: host does not support reading read-only switch. assuming write-enable.
[    2.437709] mmc2: new high speed SDHC card at address aaaa
[    2.443688] mmcblk1: mmc2:aaaa SS08G 7.40 GiB 
[    2.449549]  mmcblk1: p1


starting pid 1077, tty '/dev/console': '-/bin/sh'




BusyBox v1.20.2 (2016-11-29 16:20:44 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.


-/bin/sh: can't access tty; job control turned off
[root@osee /]# 


优化内核后,开机三秒不到!!继续优化中...


全剧终!

你可能感兴趣的:(Linux)