1. 程式人生 > >Linux啟動分析之Initramfs

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 ([email protected]) (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 <bio-0> 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
[[email protected] /]# 

優化核心後,開機三秒不到!!繼續優化中...

全劇終!