gzyueqian
13352868059
首页 > 新闻中心 > > 正文

S3C2440 从cross-tools到 linux2.6.24.4

更新时间: 2008-09-09 09:07:09来源: 粤嵌教育浏览量:2146

  • 1. 为vmware 添加新的硬盘
    fdisk 用法就算了
    mkfs -t ext3 -c /dev/sdb1 (我看就不用 -c 参数了吧, check bad block 就不用了, 俺的E4500真快阿,郁闷为啥叫sdx了呢)
    df 看看
    vim /etc/fstab 添加到系统fstab
    /dev/sdb1 /cross ext3 default 1 2
    (man fstab,mount) 不备份 fsck检查顺序

    2. cross build principle

    --------------------------------------------------------------------------------

    1) 准备source code (host:linux targe:arm-linux)
    binutils-2.18 ftp://ftp.ntu.edu.tw/pub/gnu/gnu/binutils/binutils-2.18.tar.bz2
    gcc-core-4.1.2 ftp://ftp.ntu.edu.tw/pub/gnu/gnu/gcc/gcc-4.1.2/gcc-core-4.1.2.tar.bz2
    gcc-g++4.1.2 ftp://ftp.ntu.edu.tw/pub/gnu/gnu/gcc/gcc-4.1.2/gcc-g++-4.1.2.tar.bz2
    glibc-2.6.1 ftp://ftp.ntu.edu.tw/pub/gnu//gnu/glibc/glibc-2.6.1.tar.gz
    linux-2.6.24.4 http://www.cn.kernel.org/pub/linux/kernel/v2.6/linux-2.6.24.4.tar.bz2

    --------------------------------------------------------------------------------
    2) 定义环境变量 (然后解压缩...)

    export PREFIX=/cross/cross-arm cross gcc的bin会放到这个目录
    export TARGET=arm-linux arm 上的linux

    cd /cross/src 假设你下载的gcc 和binutil在这个目录(你当然要解压缩了)
    mkdir build-binutils build-gcc build-glibc

    --------------------------------------------------------------------------------
    3) binutils (要分清host和target啊...)
    cd /cross/src/build-binutils
    ../binutils-x.xx/configure --target=$TARGET --prefix=$PREFIX --disable-nls
    make all
    make install

    --disable-nls :不要使用汉语吧, 用英语就行了. 这个选项让gcc不输出汉语的提示...

    --------------------------------------------------------------------------------
    4) bootstrap gcc
    cd /cross/src/build-gcc
    export PATH=$PATH:$PREFIX/bin
    ../gcc-x.x.x/configure --target=$TARGET --prefix=$PREFIX --disable-nls
    --enable-languages=c --without-headers --disable-shared --disable-threads --disable-libmudflap --disable-libssp
    make all-gcc
    make install-gcc

    -without-headers :这个选项使你编译出的GCC不能使用标准库.(host cpu和target cpu一样的话,基本不用cross toolchain系统通过编译选项也能实现这个功能).
    --with-newlib 这只是个bug的work around,和newlib没有关系的.
    This is only necessary if you are compiling GCC <= 3.3.x. That version has a known bug that keeps --without-headers from working correctly. Additionally setting --with-newlib is a workaround for that bug.
    --enable-languages :tell gcc需要哪些语言支持:font end, bootstrap gcc only surppot C
    tells GCC not to compile all the other language frontends it supports, but only C。
    --disable-shared : 没有这个选项,会有 crti.o: No such file: No such file or directory collect2: ld returned 1 exit status
    --disable-thread : 没有这个选项的话会有, posix_thread.h can't not found 的问题 .
    --disable-libmudflap --disable-libssp :两个边界检查使用的库,有问题,禁止

    http://www.mail-archive.com/gcc@gcc.gnu.org/msg31021.html 无libc的时候这几个库是不能编译通过的 :ssp,mudflap,gomp
    http://projects.linuxtogo.org/pipermail/openembedded-commits/2007-November/010465.html 这个线索是这个问题的补丁
    还有官方的 bug :http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25035

    --------------------------------------------------------------------------------

    5) prepare linux kernel heads

    make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig 配置内核,记着选arm哦
    make ARCH=arm CROSS_COMPILE=arm-linux- 随意运行下,就能产生version.h autoconf.h

    cd linux-2.4.21
    cp -dR include/asm-arm $PREFIX/$TARGET/include/asm
    cp -dR include/linux $PREFIX/$TARGET/include/linux

    在$TARGET/PREFIX/目录中建立下面的符号连接:

    cd $PREFIX/$TARGET
    ln -s include sys-linux 相当于configure gcc --with-heads=

    在$TARGET_PREFIX/目录中建立下面的符号连接:
    cd $PREFIX/$TARGET/include/asm
    ln -s arch-s3c2410 arch 其实arch 已经建立了 (make了下,建立好了)
    ln -s proc-armv proc 这个版本没proc这个连接了

    --------------------------------------------------------------------------------

    6) build glibc
    搞了半天,原来glibc 2.6.1 是不支持arm的, 需要打上一系列的补丁
    glibc-2.6.1-alpha_ioperm_fix-1.patch
    glibc-2.6.1-cross_hacks-1.patch
    glibc-2.6.1-hppa_nptl-1.patch
    glibc-2.6.1-libgcc_eh-1.patch
    glibc-2.6.1-localedef_segfault-1.patch
    glibc-2.6.1-mawk_fix-1.patch
    glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch
    glibc-2.6.1-sysdep_cancel-1.patch

    推荐补丁下载地址 : http://ftp.osuosl.org/pub/clfs/conglomeration/glibc/
    推荐文章: http://blog.chinaunix.net/u/26710/showart_394113.html
    RTLD_SINGLE_THREAD_P 的fix(上面的patch已经包含了,参考下):
    http://sources.redhat.com/ml/libc-ports/2006-10/msg00070.html

    用 patch -Np1 -i 猛打把,少了那个都编译不过去 ,详细步骤如下
    tar xvf glibc-2.6.1.tar.bz2
    cd glibc-2.6.1/

    tar xvf ../glibc-ports-2.6.1.tar.bz2
    mv -v glibc-ports-2.6.1 ports

    patch -Np1 -i ../glibc-2.6.1-libgcc_eh-1.patch
    patch -Np1 -i ../glibc-2.6.1-localedef_segfault-1.patch
    patch -Np1 -i ../glibc-2.6.1-cross_hacks-1.patch
    patch -Np1 -i ../glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch

    NPTL problem fix:
    patch for glibc2.4: http://www.devfiles.jlime.com/parted/glibc/nptl-crosscompile.patch
    The following lines need to be added to config.cache for Glibc to support NPTL:
    echo "libc_cv_forced_unwind=yes" > config.cache
    echo "libc_cv_c_cleanup=yes" >> config.cache
    使用参数--cache-file=config.cache
    还不行,需要把asm-generic copy 到 $PREFIX/$TARGET/include .... (为啥经验这么重要呢。。)

    $ tar -xvzf glibc-2.2.3.tar.gz
    $ tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3

    $ cd build-glibc
    $ CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix=/usr
    --with-headers=$PREFIX/$TARGET/include --cache-file=config.cache

    CC=arm-linux-gcc 把 CC 变量设成你刚编译完的boostrap gcc, 用它来编译你的glibc.
    --host=$TARGET 告诉该链接库在目标系统上执行, 而非在本地主机.
    --prefix="/usr" 告诉配置脚本在目标板的根文件系统中glibc的位置.
    --with-headers 告诉glibc 我们的linux 内核头文件的目录位置.
    --enable-add-ons 告诉配置脚本使用我们下载的附加包. 已经将glibc-linuxthreads-2.2.3放入了glibc 源码目录中.
    由于我们只添加了一个附加包, 这里--enable-add-ons等价于 --enable-add-ons=linuxthreads.
    (如果使用glibc-2.1.x, 需要使用glibc-crypt附加包, 就得使用: --enable-add-ons= linuxthreads, crypt选项). (NPTL 了 )

    $ make
    $ make install_root=$PREFIX/$TARGET prefix="" install
    install_root 指定了安装链接库组件的目录, 将glibc安装到与我们项目相关的目录, 而非/usr目录.如果不指定prefix="", 那么glibc会被安装到$/PREFIX/$TARGET/usr/lib目录中. 指定prefix使glibc被安装到 $TARGET_PREFIX/lib目录.

    --------------------------------------------------------------------------------
    7.)修改$PREFIX$TARGET/lib目录中的libc.so
    $ cd $PREFIX/$TARGET/lib
    $ cat libc.so

    libc.so的内容:

    /* GNU ld script

    Use the shared library, but some functions are only in

    the static library, so try that secondarily. */

    GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a )


    将/lib/目录去掉, 既将"GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a )"改为: GROUP ( libc.so.6 libc_nonshared.a )

    --------------------------------------------------------------------------------
    8) completed GCC

    cd build-4.1.2
    ../gcc-4.1.2/configure --target=arm-linux --prefix=/cross/cross-arm --enable-languages=c
    make
    make install

    (出鬼的顺利,不支持c++,gcc 相关补丁也没有打, 凑合先用吧)

    --------------------------------------------------------------------------------

    9) simple check
    arm-linux-gcc --print-libgcc-file-name
    arm-linux-gcc -print-search-dirs
    arm-linux-gcc -o test test.c
    arm-linux-objdump -D test

    --------------------------------------------------------------------------------
    10 build kernel for arm
    为了配置方便,copy 一个default config 到linux2.6.24.4 的根目录. 然后就剪辑吧能去的都去掉.嘿嘿.

    cp arch/arm/configs/s3c2410_defconfig .
    mv s3c2410_defconfig .config

    menuconfig:
    make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

    zImage 出来了, download 到S3C2440 看看吧. 任意键进入boot menu. 选2 downfrom uart,用DNW下载代码,完成 选4,写入nand flash. (不同系统不一样,看monitor 咋写了) 选boot os............. 操蛋,啥都没看到,
    只是在串口上看到monitor输出如下:
    Set boot params = root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000 console=ttyS1,115200 mem=65536K devfs=mount
    Load Kernel...
    Load Ramdisk...

    遇到的问题请继续看下一节...

    --------------------------------------------------------------------------------
    11 调整解压缩参数

    到底啥是重要的啊, 如果连个printf都不能用,运气未免太差. 参数中的ttyS1 (第10节的输出),俺没有注意到(么经验啊). 于是上ADS 的AXD调试:
    先连接上目标板,然后选run, 这样就可以reboot 系统,选5, boot os, 然后用ADX stop,就会看到一段汇编了. 仔细查看发现arm 确实在运行一段程序,经过查询system.map,发现是panic( 我猜想是root fs没有...,但是没有显示内容到我的串口啊,串口接在uart1上).

    随意看看那个2440 mon程序, linux的加载方式如下:

    将zImage从nand flash copy到 0x3040 0000 然后就jump过去. 内核参数放在0x3000 0100.
    goto_start = 0x3040 0000;
    (*goto_start)(0, 193);
    不过对为啥不能启动还是没有线索啊...

    有几个比较可疑的内核配置选项可能引起问题比如
    boot option->
    compressed rom boot loader base address #<a>
    default kernel command string #<b>
    所以俺又试了几个选项, 把 #<a> 的地址改成0x3040 0000...... 不幸还是不可以, 因为没有信息出现也不知道运行到了哪里,不过根据调试的结果,应该是过了解压缩阶段的....
    事后俺查上面两个选项的含义( 就是按 ? 了), #<a> 是说ROM able 的zImage, 就是zImage直接在rom中运行时, 才有效所以犯了错误啊. <b> 也不行, 因为如果没有办法传递kernel 的command line时才有效, 而s32440下无效. 帮助里列举有几个平台需要这个选项.

    先把参数地址为啥在0x3000 0100 和runaddr为啥在0x3040 0000跳过不谈,为啥没有任何信息? 连解压内核的信息都没有? 看了几遍config, 找到了如下的选项:
    system type->
    [0] S3C UART to use for low-level messages
    嘿嘿,进去把0改成1, 看看arm的相关启动代码,印证了通过这个选项选择内核解压缩信息的输出端口. 选成1, 再试,果然有内核解压缩信息打印出来,呵呵. 相关代码在内核的位置:
    decompress_kernel ->
    putstr("Uncompressing Linux...");
    gunzip();
    putstr(" done, booting the kernel. ");
    -> include/asm-arm/plat-s3c
    static void putc(int ch)
    {
    if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
    .....
    }
    uart_rd(unsigned int reg)
    {
    volatile unsigned int *ptr;

    ptr = (volatile unsigned int *)(reg + uart_base);
    return *ptr;
    }
    #define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT)

    --------------------------------------------------------------------------------
    12. 内核控制台

    就是命令行里的console参数. 这里不打算讨论console到底是啥, 仅指出,俺没有看到内核正常的启动信息和这个选项大大的相关.我们分析下monitor给出的信息:

    Set boot params = root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000 console=ttyS1,115200 mem=65536K devfs=mount
    Load Kernel...
    Load Ramdisk...

    这里console设置成了 ttyS1, 而linux2.6.24.4 要求(不知道具体从啥时候开始,2.6?) 名字是ttySAC1,指定串口1. 看monitor的代码就能知道了, monitor需要升级的. ...走了冤枉路了,明白了monitor和内核这里的一点纠缠.
    升级monitor之后... 嘿嘿,终于有东西了...呵呵

    Uncompressing Linux...................................................... done
    , booting the kernel.
    Linux version 2.6.24.4 (root@localhost.localdomain) (gcc version 4.1.2) #7
    Tue Apr 15 07:50:25 CST 2008
    CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
    Machine: SMDK2410
    ATAG_INITRD is deprecated; please update your bootloader.
    Memory policy: ECC disabled, Data cache writeback
    CPU S3C2440A (id 0x32440001)
    S3C244X: core 400.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
    S3C24XX Clocks, (c) 2004 Simtec Electronics
    CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
    CPU0: D VIVT write-back cache
    CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
    CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
    Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
    Kernel command line: root=/dev/ram init=/linuxrc initrd=0x00000000,0x00000000
    console=ttySAC1,115200 mem=65536K devfs=mount
    irq: clearing pending ext status 000dff00
    irq: clearing pending ext status 00001000
    irq: clearing subpending status 000000ba
    irq: clearing subpending status 00000092
    PID hash table entries: 256 (order: 8, 1024 bytes)
    timer tcon=00090000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8
    Console: colour dummy device 80x30
    console [ttySAC1] enabled
    Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
    Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
    Memory: 64MB = 64MB total
    Memory: 63128KB available (1428K code, 223K data, 92K init)
    Mount-cache hash table entries: 512
    CPU: Testing write buffer coherency: ok
    S3C2440: Initialising architecture
    S3C2440: IRQ Support
    S3C2440: Clock Support, DVS off
    S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
    DMA channel 0 at c4800000, irq 33
    DMA channel 1 at c4800040, irq 34
    DMA channel 2 at c4800080, irq 35
    DMA channel 3 at c48000c0, irq 36
    JFFS2 version 2.2. (NAND) 漏 2001-2006 Red Hat, Inc.
    io scheduler noop registered
    io scheduler anticipatory registered (default)
    io scheduler deadline registered
    io scheduler cfq registered
    Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
    s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
    s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
    s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
    RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
    loop: module loaded
    S3C24XX NAND Driver, (c) 2004 Simtec Electronics
    s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
    NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-
    bit)
    Scanning device for bad blocks
    Creating 8 MTD partitions on "NAND 64MiB 3,3V 8-bit":
    0x00000000-0x00004000 : "Boot Agent"
    0x00000000-0x00200000 : "S3C2410 flash partition 1"
    0x00400000-0x00800000 : "S3C2410 flash partition 2"
    0x00800000-0x00a00000 : "S3C2410 flash partition 3"
    0x00a00000-0x00e00000 : "S3C2410 flash partition 4"
    0x00e00000-0x01800000 : "S3C2410 flash partition 5"
    0x01800000-0x03000000 : "S3C2410 flash partition 6"
    0x03000000-0x04000000 : "S3C2410 flash partition 7"
    mice: PS/2 mouse device common for all mice
    S3C24XX RTC, (c) 2004,2006 Simtec Electronics
    s3c2440-i2c s3c2440-i2c: slave address 0x10
    s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz
    s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
    S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
    s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
    drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
    List of all partitions:
    1f00 16 mtdblock0 (driver?)
    1f01 2048 mtdblock1 (driver?)
    1f02 4096 mtdblock2 (driver?)
    1f03 2048 mtdblock3 (driver?)
    1f04 4096 mtdblock4 (driver?)
    1f05 10240 mtdblock5 (driver?)
    1f06 24576 mtdblock6 (driver?)
    1f07 16384 mtdblock7 (driver?)
    No filesystem could mount root, tried: cramfs romfs
    Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)

    --------------------------------------------------------------------------------
    13. 内核参数的传递方式

    前边说过monitor吧内核参数放到了地址 0x3000 0100 这个地址. 这个道理何在呢. 先看内核打印内核命令行的地方: init/main.c
    asmlinkage void __init start_kernel(void)
    -->printk(KERN_NOTICE "Kernel command line: %s ", boot_command_line);
    是个全局变量,搜索下,在arch/arm/kernel/setup.c:
    void __init setup_arch(char **cmdline_p)
    {
    char *from = default_command_line; /*.config 中指定的命令行*/
    ...
    mdesc = setup_machine(machine_arch_type); /*从上面串口输出知道是 "Machine: SMDK2410", 由.config决定*/
    /*里边引用的lookup_machine_type 在arch/arm/kernel/head_common.S*/
    ......
    if (__atags_pointer)
    tags = phys_to_virt(__atags_pointer);
    else if (mdesc->boot_params)
    tags = phys_to_virt(mdesc->boot_params);
    ...
    /*
    * If we have the old style parameters, convert them to
    * a tag list.
    */
    if (tags->hdr.tag != ATAG_CORE)
    convert_to_tag_list(tags); /*把boot loader传递的参数, arch/arm/kernel/compat.c struct param_struct {
    ..} 转换成tag list, 其中包括 ATAG_CMDLINE */
    if (tags->hdr.tag != ATAG_CORE)
    tags = (struct tag *)&init_tags;

    if (mdesc->fixup) /*s3c2410 是NULL*/
    mdesc->fixup(mdesc, tags, &from, &meminfo);

    if (tags->hdr.tag == ATAG_CORE) {
    if (meminfo.nr_banks != 0)
    squash_mem_tags(tags);
    parse_tags(tags); /*ATAG_CMDLINE 的parser 把相应命令行copy 到default_command_line, 也在这个文件内*/
    }

    ....
    memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
    boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
    parse_cmdline(cmdline_p, from);
    }

    这里先忽略下mdesc是怎么被找到的,先直接搜索 mdesc的类型,可以找到 #define MACHINE_START(_type,_name) 这个宏,然后console的"SMDK2410"这个宏定义, 可以在arch/arm/mach-s3c2410下找到:

    MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
    * to SMDK2410 */
    /* Maintainer: Jonas Dietsche */
    .phys_io = S3C2410_PA_UART,
    .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    .boot_params = S3C2410_SDRAM_PA + 0x100,
    .map_io = smdk2410_map_io,
    .init_irq = s3c24xx_init_irq,
    .init_machine = smdk2410_init,
    .timer = &s3c24xx_timer,
    MACHINE_END

    #define S3C2410_SDRAM_PA (S3C2410_CS6)
    #define S3C2410_CS6 (0x30000000)

    这下子就知道内核参数传递的方式了: (arm)
    把 arch/arm/kernel/compat.c 中定义的struct param_struct { } 放到0x3000 0100 处即可....

    至于去求证 monitor 的 runAddr 和参数地址, 请看 : (这个是monitor用到的参数,决定了runAddrs)

    BootParams boot_params = {
    {"bootpara", 1}, //0=boot without parameters,1=boot with parameters
    {"cpuclk", 2}, //0=200M, 1=300M, 2=400M, 3=440M
    {"rundelay", 0}, //0 seconds
    {"serial", 1}, //0=serial port 0, 1=serial port 1
    {"baudrate", 115200},
    {"machine", 193},
    {"runAddr", 0x30400000},
    {"rootfs", 0},
    {"tty", 1},
    {"initrdA", 0},
    {"initrdL", 0},
    {"memsize", 0x04000000},
    {"devfs", 1},
    {"ostore", 0}, //0=nand, 1=nor
    {"userpara", sizeof(DEFAULT_USER_PARAMS)},
    DEFAULT_USER_PARAMS
    };
    从这个参数加载linux的代码在nand.c LoadRun .

    --------------------------------------------------------------------------------

    14. 内核加载地址和start参数问题
    从上面的分析, 知道内核被加载到0x30400 0000处, 这个其实是zImage的加载地址, 就是说内核解压缩程序的运行地址. 还有一个问题,我们的内核一直是little endian 的. arm-linux-objdump下就知道.
    一个问题是Big-endian的内核如何run, 另一个是解压缩程序的运行地址是随意的吗?

    从monitor看, 这个环境一直在little endian运行... (big endian 实验也另作研究吧)

    能否加载到任意合理地址(至少有ram吧,呵呵), 试验一下即可. 结果证明是可以的, 当然应该行,因为zImage已经支持PIC代码,并且可以配置成在纯ROM环境下运行(那就得烧到到固定地址了).

    研究下zImage都包含什么东西,这个先从arch/arm/boot/Makefile看看吧:

    $(obj)/compressed/vmlinux: $(obj)/Image FORCE
    $(Q)$(MAKE) $(build)=$(obj)/compressed $@

    $(obj)/zImage: $(obj)/compressed/vmlinux FORCE #zImage 包含解压缩头的Image
    $(call if_changed,objcopy)
    @echo ' Kernel: $@ is ready'

    .......
    $(obj)/uImage: $(obj)/zImage FORCE # U-boot image
    $(call if_changed,uimage)
    @echo ' Image $@ is ready'

    $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE 包含bootp目录的image bootpImage, 如要initrd,这个平台不支持,所以加载
    $(Q)$(MAKE) $(build)=$(obj)/bootp $@ RamDisk 是monitor的事情了
    @:

    $(obj)/bootpImage: $(obj)/bootp/bootp FORCE #包含bootp目录的image bootpImage
    $(call if_changed,objcopy)
    @echo ' Kernel: $@ is ready'


    内核解压缩和PIC (position independent code)
    arch/arm/boot/compressed/Makefile

    #
    # We now have a PIC decompressor implementation. Decompressors running
    # from RAM should not define ZTEXTADDR. Decompressors running directly
    # from ROM or Flash must define ZTEXTADDR (preferably via the config)
    # FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK
    ifeq ($(CONFIG_ZBOOT_ROM),y) #从boot ROM运行时需要配置一个固定地址,还有BSS的地址
    ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
    ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
    else
    ZTEXTADDR := 0 #一般情况下,就是0, 是pic代码加上'手工'重定位,加载到任意地址
    ZBSSADDR := ALIGN(4)
    endif

    SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
    #把vmlinux.lds.in 中TEXT_START换成配置的地址(主要针对ZBOOT_ROM)

    targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c
    head.o misc.o $(OBJS)
    EXTRA_CFLAGS := -fpic -fno-builtin
    EXTRA_AFLAGS :=
    .............
    # Don't allow any static data in misc.o, which
    # would otherwise mess up our GOT table
    CFLAGS_misc.o := -Dstatic=

    $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o
    $(addprefix $(obj)/, $(OBJS)) FORCE
    $(call if_changed,ld)
    @:

    $(obj)/piggy.gz: $(obj)/../Image FORCE #piggy.gz 是压缩后的内核,见piggy.S
    $(call if_changed,gzip)

    $(obj)/piggy.o: $(obj)/piggy.gz FORCE

    CFLAGS_font.o := -Dstatic=

    $(obj)/font.c: $(FONTC)
    $(call cmd,shipped)

    $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
    @sed "$(SEDFLAGS)" < $< > $@

    $(obj)/misc.o: $(obj)/misc.c include/asm/arch/uncompress.h lib/inflate.c

    解压缩的pic技术以后再研究吧,挺多的.这里就是增强下信心吧. 知道可以加载到任意地址,呵呵. 下面看看decompress的入口函数start的参数问题:
    arch/arm/boot/compressed/head.S
    /*
    * sort out different calling conventions
    */
    .align
    start:
    .type start,#function
    .rept 8
    mov r0, r0
    .endr

    b 1f
    .word 0x016f2818 &nb sp; @ Magic numbers to help the loader
    .word start @ absolute load/run zImage address
    .word _edata @ zImage end address
    1: mov r7, r1 @ save architecture ID
    mov r8, r2 @ save atags pointer

    从这里看出, r1 存放的是architectureID, r2存放 atags 指针. 寄存器传递参数, 加上没有用的r0, 应该是这样一个函数:

    void start(0, archID, *atags)
    其实,在arch/arm/kernel/head.S中有关于参数的一段详细的注释,看看就明白了:
    /*
    * Kernel startup entry point.
    * ---------------------------
    *
    * This is normally called from the decompressor code. The requirements
    * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
    * r1 = machine nr, r2 = atags pointer.
    *
    * This code is mostly position independent, so if you link the kernel at
    * 0xc0008000, you call this at __pa(0xc0008000).
    *
    * See linux/arch/arm/tools/mach-types for the complete list of machine
    * numbers for r1.
    *
    * We're trying to keep crap to a minimum; DO NOT add any machine specific
    * crap here - that's what the boot loader (or in extreme, well justified
    * circumstances, zImage) is for.
    */
    找到mach-type是:
    s3c2440 ARCH_S3C2440 S3C2440 362
    不过通过实验, 我们的机器看来是SMDK兼容了,machine 参数必须传递193: SMDK2410 这个才行,而cpu类型则是自动侦测的,呵呵.

    对应kernel的参数和decompressed一样:

    void (*theKernel)(int zero, int arch, uint params);

    另:试了试big endian,发现现在linux kernel对s3c的系统还不支持big模式.make config也无此选项.

    --------------------------------------------------------------------------------
    15. initrd : initial ram disk load process
    让我们从新审视所得到的内核console的输出(见上文),看看需要做的东西, 先来关注几行的输出信息,内核相关代码是:

    start_kernel->rest_init->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);->
    static int __init kernel_init(void * unused)
    {
    ..........
    /*
    * check if there is an early userspace init. If yes, let it do all
    * the work
    */

    if (!ramdisk_execute_command) /*由内核命令行参数 rdinit= 来控制,我们没有指定 (搜索就知道是rdinit=来控制了...)*/
    ramdisk_execute_command = "/init";

    if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
    ramdisk_execute_command = NULL;
    prepare_namespace();
    }
    .........
    }

    内核中有各种__setup宏定义的内核参数, 其前面的字符串是内核命令行, 其后的函数是这个命令行的处理函数,相关的宏定义在init.h中.grep下,很快有结果. 详细讨论先放一放.
    void __init prepare_namespace(void)
    {
    .............
    if (saved_root_name[0]) {
    root_device_name = saved_root_name; /*这个就是由 root=/dev/ram传递的内核参数,稍作搜索即知*/
    if (!strncmp(root_device_name, "mtd", 3)) { /*我们当然不是这个*/
    .............
    }
    ROOT_DEV = name_to_dev_t(root_device_name); /*/dev/ram 解析出来的设备是 ROOT_DEV= root_RAM0(1,0)*/
    if (strncmp(root_device_name, "/dev/", 5) == 0)
    root_device_name += 5; /* root_dev_name = "ram" */
    }

    if (initrd_load()) /* CONFIG_BLK_DEV_INITRD 之后才能使用initrd,我们的.config是有的*/
    goto out;
    ......
    mount_root();
    out:
    sys_mount(".", "/", NULL, MS_MOVE, NULL); /* /root 如何成为根, 何以叫mount root,原来并不是加载 "/" */
    sys_chroot(".");
    security_sb_post_mountroot();
    }

    int __init initrd_load(void)
    {
    if (mount_initrd) { /*只有配置了内核命令行: noinitrd才为0, 我们当然没有'自杀'了*/
    create_dev("/dev/ram", Root_RAM0); /*创建设备先...*/
    /*
    * Load the initrd data into /dev/ram0. Execute it as initrd
    * unless /dev/ram0 is supposed to be our actual root device,
    * in that case the ram disk is just set up here, and gets
    * mounted in the normal path.
    */
    if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { /*下面看看/initrd.image啥时候创建的*/
    sys_unlink("/initrd.image");
    handle_initrd();
    return 1;
    }
    }
    sys_unlink("/initrd.image");
    return 0;
    }

    从我们配置的参数是Root_RAM0, void __init prepare_namespace(void)会调用mount_root:

    void __init mount_root(void)
    {
    #ifdef CONFIG_ROOT_NFS
    ...
    #endif
    #ifdef CONFIG_BLK_DEV_FD
    ....
    #endif
    #ifdef CONFIG_BLOCK
    create_dev("/dev/root", ROOT_DEV);
    mount_block_root("/dev/root", root_mountflags); /*有默认值 MS_RDONLY | MS_SILENT*/
    #endif
    }
    void __init mount_block_root(char *name, int flags)
    {
    get_fs_names(fs_names); /*所有已经安装的文件系统的名字列表*/
    retry:
    for (p = fs_names; *p; p += strlen(p)+1) { /*p代表fs type, 这里name 是/dev/root,就是Root_RAM0*/
    int err = do_mount_root(name, p, flags, root_mount_data); /*(dev,type,mntflags,(rootflags=,给具体文件系统的参数) )*/
    .......
    /*如果失败了,下面的信息倒是没有显示出来....*/
    printk("VFS: Cannot open root device "%s" or %s ",
    root_device_name, b);
    printk("Please append a correct "root=" boot option; here are the available partitions: ");

    printk_all_partitions();
    panic("VFS: Unable to mount root fs on %s", b);
    }

    printk("List of all partitions: ");
    printk_all_partitions();
    printk("No filesystem could mount root, tried: "); /*列出曾经尝试的文件系统类型*/
    for (p = fs_names; *p; p += strlen(p)+1)
    printk(" %s", p);
    printk(" ");
    .......
    panic("VFS: Unable to mount root fs on %s", b); /*知名panic*/
    ...
    }

    好了上面的函数就是知名的panic. 这个过程就是将文件/initrd.image 拷贝到Root_RAM0设备内, 然后创建设备文件/dev/root(这个个文件就是为了fs的接口函数准备的),然后将 /dev/root 安装到/root, 升级/root到文件系统根目录 '/'.

    遇到这个panic从代码上看,是do_mount_root在尝试用各种文件系统来解析/dev/root后竭尽失败.无奈之下,panic的.原因可就多了,比如config的时候没有选上ramdisk支持(设备层), 或者ramdisk中的文件系统内核不支持(文件系统层), 再或者initrd的加载出了问题(无论是boot loader 还是内核创建"/initrd.image", 参数传递错误也不成. 经过仔细检查,内核配置和参数传递应该没有啥问题. 这里好多内核的信息没有打印出来,详细的错误也就被隐蔽了.
    为了验证ramdisk是否正确加载, 在rd_load_image("/initrd.image") 里面加了不少调试信息,结果发现, 根本没有/initrd.image这个文件,在这个函数打开这个文件的时候出错了, 这证明这个文件创建失败了. 原因也很多,不过还是先扫一眼这个文件在什么地方创建.一搜,在这个函数里呢:

    static int __init populate_rootfs(void) 这是一个init函数,内核悄悄的运行了他.... (运行的地方好找,不提).
    static int __init populate_rootfs(void)
    {
    ... /*解压缩先略过不看...*/
    if (initrd_start) { /*这个就是内核命令行传递进来的值...., 汗...monitor里这个值是0, 显然是不对的啊*/
    /* ...创建 initrd.image 这个文件*/
    fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
    .......
    }

    好了一个问题出来了, 改吧, 去monitor的参数里修改一番,也犯了不少错误:
    1) 个就是initrd的初始地址不能为0...,

    2) 再有就是有个地方出错比如我设置initrd初始地址0x1000(随意值), 大小是0x1000(随意值,不设置长度monitor不加载ramdisk,只对此monitor有效). 这个地址有傻问题? 看看输出:
    Memory policy: ECC disabled, Data cache writeback
    initrd (0x00000000 - 0x000003e8) extends beyond physical memory - disabling initrd
    CPU S3C2440A (id 0x32440001)
    这里又跳出个地方和initrd有关, 位置在bootmem初始化中:(ft...)
    arch/arm/mm/init.c
    static int __init check_initrd(struct meminfo *mi)
    {
    .......
    if (phys_initrd_size) {/*初传递的initrd start 和size都是0, 我ft.... */
    for (i = 0; i < mi->nr_banks; i++) {
    ...........
    }

    if (initrd_node == -1) {
    printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond "
    "physical memory - disabling initrd ",
    phys_initrd_start, end);
    phys_initrd_start = phys_initrd_size = 0;
    }
    ..........
    }
    没有仔细探究这个bank是个什么意思(估计就是S3C2440 cpu里对内存bank的划分吧),但是这个警告信息提醒了我.超出物理内存? 不一定是地址太大,呵呵,因为啊, ram物理地址并不是从0开始的,启动的时候是S3C2440 自己吧nand读到了地址0开始的一段内部ram中.....所以,吧initrd start地址和size设置成一个在RAM地址范围内的一段地址里. 重启,这下,果然不同了........
    出现的信息还是不能加载root文件系统,但是initrd加载成功了, 即ramdisk已经包含了initrd.image, "/initrd.image"文件也已经创建成功了. 但是出现RAMDISK: image too big! (2078xx/4096) ,相关函数是

    int __init rd_load_image(char *from) /*从/initrd.image 写入/dev/ram设备*/
    {
    ......
    /*nblocks是从ramdisk image中根据文件系统magic猜测的block数(identify_ramdisk_image),
    *rd_blocks是从/dev/ram设备中读出的数值,ramdisk大小是4096K size ,1024 blocksize,可以配置
    */
    if (nblocks > rd_blocks) { /*这个信息是发现加载的initrd image大小大于ram disk的大小,加载失败*/
    printk("RAMDISK: image too big! (%dKiB/%ldKiB) ",
    nblocks, rd_blocks);
    goto done;
    }
    ....
    }
    另外,建议调试阶段把kernel consolelog 设置成verbose,就是在setup_arch的前端,调用下面函数:
    console_verbose();
    这样一些提示性和continue性质的信息能够显示出来方便调试.

    这个原因是什么? 根据调试信息打印出来信息, identify_ramdisk_image:RAMDISK: cramfs filesystem found at block 0
    显然是发现了一个cramfs,但是不知到是什么原因. 呵呵,秘密是我还没有烧一个initrd进去呢,用的是现有的, 其大小和格式都是未知的.这样当然累了,要知道原因就太难(?), 所以要自己制作一个....

    --------------------------------------------------------------------------------
    16. 制作ramfs

    为了测试,仅制作文件系统..步骤如下:
    RDSIZE=1024
    BLKSIZE=1024
    # 为了测试,越小越好,创建一个1M 的ram disk,这样下载快(现在我只有串口)
    dd if=/dev/zero of=ramdisk.img bs=$BLKSIZE count=$RDSIZE
    #在其上制作ext2文件系统
    /sbin/mke2fs -F -m 0 -b $BLKSIZE ramdisk.img $RDSIZE
    -F 强制运行,不管是否是块设备/或者已经安装
    -m 0 设置预留块数量的百分比, 我们可不能浪费,所以一个都不保留....呵呵.
    -b 1024 一个block 1k
    下载,运行,呵呵又出错了:
    try load ram disk /*这是自己加的调试信息*/
    RAMDISK: ext2 filesystem found at block 0 /*我们制作的是ext2文件系统,这里也认出了*/
    RAMDISK: Loading 4000KiB [1 disk] into ram disk... done. /*这里看出initrd真是加载成功了,到了ramdisk0中*/
    load image ret 1 /*这是自己加的调试信息, mount失败*/
    原因很明显,我们根本没有编译ext2文件系统支持, 重新配置编译,运行.呵呵根文件系统安装真的成功了.不过,问题还没有完:
    VFS: Mounted root (ext2 filesystem).
    Freeing init memory: 92K
    Warning: unable to open an initial console.
    Failed to execute /linuxrc. Attempting defaults...
    Kernel panic - not syncing: No init found. Try passing init= option to kernel.
    这个嘛,嘿嘿,我们的文件系统上啥都没有, 得搞个什么东西上去才行啊.
    --------------------------------------------------------------------------------

    16.1 initrd "hello world"
    也试了直接编译busybox,可是看起来busybox启动了,但是没有任何输出.查busybox的说明,busybox建议自己用cross toolchain搞个hello world试试,看看你能不能运行,不行的话就别搞busybox了,肯定不行啦.
    故而,写hello world一个(好久不hello world了):
    arm-linux-gcc -static -o test test.c
    arm-linux-objcopy -S test test_strip [这个去掉大部分没有用的段,大大减小bin的大小]
    然后用arm-linux-readelf -A test 看看. (aeabi) 在rootfs上(ramdisk.img)建立/dev和必要的设备文件:
    mount -t ext2 ramdisk.img /mnt/initrd -o loop
    mkdir dev
    cp -a /dev/null dev
    cp -a /dev/console dev
    cp /cross/src/linux2.6.24.4/test_strip linuxrc [我们的hello world就是linuxrc,呵呵]
    sync
    umount /mnt/initrd
    gzip -9 ramdisk.img
    下载, 启动.... 没有看到我熟悉的hello world
    VFS: Mounted root (ext2 filesystem).
    Freeing init memory: 92K
    selected clock c01adf24 (pclk) quot 26, calc 115740
    google下,发现自己几乎犯过了所有的毛病,先是内核并不支持eabi串口无输出,就编译成支持eabi的内核,结果一样不幸.再google,发现float point emulation必须选一,我没选,选上重来. 终float point终于解决了这个问题.内核中只能使用浮点模拟,运行大部分的 binaries 都需要浮点支持.
    hello world终于搞定了. (经测试,没有eabi支持的内核照样可以hello world,以后再研究吧]
    VFS: Mounted root (ext2 filesystem).
    Freeing init memory: 92K
    selected clock c01adf24 (pclk) quot 26, calc 115740
    hello world [这就是我们期待的输出...]

    --------------------------------------------------------------------------------

    16.2 busy box
    先编译一个busybox用用,到 http://www.busybox.net/downloads/ 下载的1.9.2玩玩.
    配置的时候选上 don't use /usr,不然make install 就完蛋了
    make ARCH=arm CROSS_COMPILE=arm-linux- allnoconfig
    make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig /*只要ash mount echo ls cat ps dmsg sysctl, static 连接*/
    make ARCH=arm CFLAGS="-I/cross/cross-arm/arm-linux/sys-include/" CROSS_COMPILE=arm-linux-
    make ARCH=arm CFLAGS="-I/cross/cross-arm/arm-linux/sys-include/" CROSS_COMPILE=arm-linux- install
    (需要把applets.c的警告去掉, glibc静态连接不好用,有bug,我们就试试,玩玩, 建议用ulibc,呵呵)然后就开始制作了:
    # 把我们先前制作的ramdisk.img加载到临时目录
    mount ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0
    # busy box 为我们建立好了各种符号连接,copy即可
    cp -rf /cross/src/busybox-1.9.2/_install/* .
    我们的rootfs就有了 bin sbin 和linuxrc
    # 然后在ramdisk上建立如下目录
    mkdir dev
    # 创建相应的设备文件
    cp -a /dev/console dev
    cp -a /dev/null dev
    #cp -a /dev/ttyS0 dev #没用s3c2410上串口设备是s3c2410_serial1
    #cp -a /dev/ttyS1 dev #
    # 解除安装, 可以压缩的(俺的很小,不压缩也罢!)
    umount /mnt/initrdgzip -9 ramdisk.img
    #先搞这么多,先玩一把,下面是输出,爽啊
    FS: Mounted root (ext2 filesystem).
    Freeing init memory: 92K
    selected clock c01a9df0 (pclk) quot 26, calc 115740
    selected clock c01a9df0 (pclk) quot 26, calc 115740
    init started: BusyBox v1.9.2 (2008-04-18 22:44:50 CST)
    selected clock c01a9df0 (pclk) quot 26, calc 115740
    command='reboot' action=32 tty=''
    command='umount -a -r' actselected clock c01a9df0 (pclk) quot 26, calc 115740ion=64 tty=''
    command='init' action=128 tty=''
    command='-/bin/sh' action=4 tty=''
    command='-/bin/sh' action=4 tty='/dev/tty2'
    command='-/bin/sh' action=4 tty='/dev/tty3'
    command='-/bin/sh' action=4 tty='/dev/tty4'
    command='/etc/init.d/rcS' action=1 tty=''
    starting pid 720, tty '': '/etc/init.d/rcS'
    Cannot run '/etc/init.d/rcS': No such file or directory
    waiting for enter to start '/bin/sh'(pid 721, tty '')
    Please press Enter to activate this console.
    Can't open /dev/tty3: No such file or directory
    Can't open /dev/tty4: No such file or directory
    process '-/bin/sh' (pid 724) exited. Scheduling it for restart.
    process '-/bin/sh' (pid 726) exited. Scheduling it for restart.
    Can't open /dev/tty3: No such file or directory
    Can't open /dev/tty4: No such file or directory(不断重复中,看看需要做的东西还多着呢,不过ash已经启动了...ls可以工作的..呵呵)
    这个事情有人报告是个bug:
    http://groups.google.com/group/linux.debian.bugs
    关于这个问题的报告 既然如此,先升级的1.10.1看看, 测试结果:
    1. applets.c的警告没有了
    2. make ARCH=arm CROSS_COMPILE=arm-linux- CFLAGS=-I/cross/cross-arm/arm-linux/sys-linux这次busybox选的东西比较多,弄了个2M的ramdisk, 压缩后399k. ...
    问题一样地...,好了自己写linuxrc吧.
    --------------------------------------------------------------------------------

    16.3 为busybox 配置脚本
    1) 先简单看看各种文件系统的作用吧:
    tmpfs :/dev/shm #share mem对应的文件系统
    devpts :/dev/pts #目前常见的 pseudo 终端(PTYs)实现方式
    sysfs :/sys #sysfs 包含进程相关的proc fs,设备相关的devfs以及为终端相关的devpty fs的信息,是当前趋势,
    由内核内的kobj形成,udev严重依赖于sysf,能够在/dev目录下产生系统真正存在的设备,而不是一锅粥的方式
    sysfs和udev配合,势必要击败devfs+devfsd(?)
    udev : # 需要/etc/udev/rules.d 目录和一堆的配置规则
    devfs :/dev #和devfsd配合使用, devfsd将会负责创建“旧类型”兼容性设备节点;在注册/注销设备时执行自动化操作; 负责备份对根文件系统上某个目录的设备许可权和所有权的更改,以及其它更多功能
    proc :proc # proc文件系统,不必多说

    2) 简单的inuxrc:
    #!/bin/she
    cho echo "Open ARM AKAE www.linuxforum.net "
    echo
    mount -t proc /proc /proc
    mount -t sysfs sysfs /sys
    mount -t devpts devpts /dev/pts
    echo "Start mdev..."
    mdev -s /*mdev -s 把设备从sysfs 同步到/dev目录,需要要/etc/mdev.conf*/
    init /*传递给脚本inittab...*/

    3) /etc/inittab
    s3c2410_serial1::respawn:-/bin/sh #/*注意s3c2410上串口的设备名称是/dev/s3c2410_serial[0..3]*/

    4) /etc/mdev.conf
    #空文件,有就行,用了在说吧

    5) 启动信息
    Open ARM www.linuxforum.net akae
    Start mdev...
    selected clock c0239b70 (pclk) quot 26, calc 115740
    init started: Busyselected clock c0239b70 (pclk) quot 26, calc 115740
    Box v1.10.1 (2008-04-19 15:27:01 CST)
    command='-/bin/sh ' action=2 tty='/dev/s3c2410_serial1'
    starting pid 229, tty '/dev/s3c2410_serial1': '-/bin/sh '
    BusyBox v1.10.1 (2008-04-19 15:27:01 CST) built-in shell (ash)
    Enter 'help' for a list of built-in commands.
    #

    6) Trouble shoot
    (1) /bin/sh: can't access tty; job control turned off
    busybox 通过系统控制台来做些工作, 如果我们的shell启动在 /dev/console (5,1)上, tty_io.c 函数open中noctty就被设置成1,导致这个问题,具体原因还不知道.总之要启动在一个真实的串口就没有关系.
    解决方法可以通过busybox的init指定shell的设备, 注意, S3C2410上, 串口1是s3c2410_serial1.终就是在etc/inittab中加入下面一句话就可以了:
    s3c2410_serial1::respawn:-/bin/sh #/*注意s3c2410上串口的设备名称是/dev/s3c2410_serial[0..3]*/
    (2)busybox的init脚本问题 no tty3 tty4 之类
    可以先启动mdev, (mdev -s), 然后运行init就可以了.
    就是让/dev/tty0-4 都存在即可.... (具体原因未知)
    (3) 加载mtdblock3 的jffs2文件系统出现下述信息:
    jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x0001001c: 0x3c04
    建议:将此分区数据清除,更近一步,加载一个image到这个分区.
    (4)下载了新内核,ramdisk找不到了
    runaddr 和 ramdisk距离太近, 内核解压缩后覆盖了ramdisk... ft
    --------------------------------------------------------------------------------

    16.4 busy box的init 和各种脚本的分工
    看到上面的脚本...写的不咋样,甚至都不符合各种配置文件的具体分工,很不规整. 下面来研究一个比较规整的方案. 下面是google结果(看busybox init的代码?,人生苦短,以后把)
    1)在串口上启动 shell
    为了避开在busybox "job control"的那个问题, 把/dev/console 直接改成 s3c2410_serial1的设备号,就是:
    mknod -m 666 console c 204 65 #204, 64,65,66
    然后直接用busybox _install目录下的linuxrc,到busybox的一个软连接,也是启动init.

    2)busybox init的流程
    简单说,就是执行inittab里指定的命令.具体流程如下:
    a)如果没有/etc/inittab,则默认执行/etc/init.d/rcS (见下面说明)
    b)执行inittab中动作类型为wait的命令
    c)执行inittab中动作类型是once的命令
    d)然后进入等待和循环执过程:
    .如果一动作为respawn类型的进程退出了,就重新启动它.
    .如果动作为askfirst类型的程序退出了,也要重新启动它,但是先询问用户.
    busybox的inittab的语法格式是: (examples/inittab)
    id:runlevels:action:process
    id: busybox 用id域指定程序运行的控制台. 如果是串口控制台,id域
    runlevels: busybox根本不使用它
    action: 字段定义了该进程应该运行在何种状态下:
    sysinit :boot time时执行 (此运行init的时候?)
    respawn :init 监视其启动的进程,如果退出了,这种类型的进程需要重新启动
    askfirst:和respawn差不多,就是要按下回车键才运行
    wait : 要等待其运行完成
    once : 只运行一次
    ctrlaltdel : 这个组合键按下时启动.

    busybox init的默认动作:
    ::sysinit:/etc/init.d/rcS
    ::askfirst:/bin/sh
    如果/dev/console 不是串口终端则继续运行:
    tty2::askfirst:/bin/sh

    3) inittab
    #在pc机上这个inittab本来是定义运行级别来着,这里就简单这么写吧
    ::sysinit:/etc/init.d/rcS
    console::askfirst:-/bin/sh #我们把console换成了串口

    4)etc/init.d/rcS
    #!/bin/sh
    echo
    echo "Open ARM AKAE-www.linuxforum.net "
    echo
    mount -t proc /proc /proc
    mount -t devpts devpts /dev/pts
    echo "Start mdev..."
    # read the busybox docs: mdev.txt, you need config your kernerl with hotplug surport
    mount -t sysfs sysfs /sys
    echo /sbin/mdev > /proc/sys/kernel/hotplug
    mdev -s

    5)一个空的/etc/mdev.conf文件先对付着

    6)/etc/fstab也没有做

    --------------------------------------------------------------------------------
    17.内核启动信息分析

    Uncompressing Linux...................................................... done
    , booting the kernel. [archarmootcompressedmisc.c: decompress_kernel()]
    Linux version 2.6.24.4 (root@localhost.localdomain) (gcc version 4.1.2) #7
    Tue Apr 15 07:50:25 CST 2008 [init/main.c :start_kernel]
    CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177 [start_kernel->setup_arch->setup_processor]
    Machine: SMDK2410 [setup_arch->setup_machine]
    Converting old-style param struct to taglist [setup_arch->convert_to_tag_list->..->build_tag_list]
    ATAG_INITRD is deprecated; please update your bootloader. [setup_arch->parse_tags->parse_tag_initrd ]
    Memory policy: ECC disabled, Data cache writeback [setup_arch->paging_init->build_mem_type_table]
    On node 0 totalpages: 16384 [setup_arch->paging_init->bootmem_init_node->free_area_init_node-> calculate_node_totalpages]
    DMA zone: 128 pages used for memmap [setup_arch->..->free_area_init_node->free_area_init_core]
    DMA zone: 0 pages reserved
    DMA zone: 16256 pages, LIFO batch:3
    Normal zone: 0 pages used for memmap
    Movable zone: 0 pages used for memmap

    CPU S3C2440A (id 0x32440001) [setup_arch->paging_init->devicemaps_init->mdesc->smdk2410_map_io->s3c24xx_init_io]
    S3C244X: core 400.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz [..smdk2410_map_io->cpu_ids->s3c244x_init_clocks]
    S3C24XX Clocks, (c) 2004 Simtec Electronics [...s3c244x_init_clocks->s3c24xx_setup_clocks]
    CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on [...s3c244x_init_clocks->s3c2410_baseclk_add]

    CPU0: D VIVT write-back cache [setup_arch->cpu_init->dump_cpu_info]
    CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
    CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
    Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256 [start_kernel->build_all_zonelists]
    Kernel command line: root=/dev/ram init=/linuxrc initrd=0x30a00000,0x00100000 [start_kernel, print cmd line ]
    console=ttySAC1,115200 mem=65536K devfs=mount
    irq: clearing pending ext status 000dff00 [start_kernel->init_IRQ->init_arch_irq(mdesc->init_irq)->s3c24xx_init_irq]
    irq: clearing pending ext status 00001000 [init_arch_irq 在arm体系下是一个函数指针,setup_arch初始化其为mdesc->init_irq]
    irq: clearing subpending status 0000009a
    irq: clearing subpending status 00000092
    PID hash table entries: 256 (order: 8, 1024 bytes) [start_kernel->pidhash_init]
    timer tcon=00090000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8 [start_kernel->time_init->system_timer.init->
    s3c2410_timer_init->s3c2410_timer_setup]
    [setup_arch中初始化全局函数指针 system_timer = mdesc->timer ,既s3c24xx_timer, arch/arm/plat-s3c24xx/timer.c]
    Console: colour dummy device 80x30 [start_kernel->console_init-> via lds __con_initcall_start ->vt:con_init]
    selected clock c0239b70 (pclk) quot 26, calc 115740 [console_initcall(s3c24xx_serial_initconsole)->register_console->console.setup->
    s3c24xx_serial_console.setup(s3c24xx_serial_console_setup)->uart_set_options->s3c24xx_serial_set_termios->s3c24xx_serial_getclk]console [ttySAC1] enabled [console_initcall(s3c24xx_serial_initconsole)->register_console]
    Dentry cache hash table entries: 8192 (order: 3, 32768 bytes) [start_kernel->vfs_caches_init_early]
    Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
    Memory: 64MB = 64MB total [start_kernel->mem_init]
    Memory: 61440KB available (2060K code, 248K data, 108K init)
    Calibrating delay loop... 199.47 BogoMIPS (lpj=498688) [start_kernel->calibrate_delay]
    Mount-cache hash table entries: 512 &n bsp; [start_kernel-> vfs_caches_init->mnt_init]
    CPU: Testing write buffer coherency: ok [start_kernel->check_bugs->check_writebuffer_bugs]
    net_namespace: 64 bytes [start_kernel->rest_init->kernel_init->do_basic_setup->pure_initcall(net_ns_init)]
    NET: Registered protocol family 16 [core_initcall(netlink_proto_init)->sock_register]
    S3C2440: Initialising architecture [arch_initcall(s3c_arch_init)->(cpu->init())->cpu_ids->s3c2410_init]
    S3C2440: IRQ Support [arch_initcall(s3c2440_irq_init)->sysdev_driver_register->drv.add()->s3c2440_irq_add]
    S3C2440: Clock Support, DVS off [arch_initcall(s3c24xx_clk_driver)->s3c2440_clk_driver.s3c2440_clk_add]
    S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics [arch_initcall(s3c2410_dma_drvinit)->sysdev_driver_register->
    DMA channel 0 at c4800000, irq 33 c2410_dma_driver.s3c2410_dma_add->s3c2410_dma_init->s3c24xx_dma_init]
    DMA channel 1 at c4800040, irq 34
    DMA channel 2 at c4800080, irq 35
    DMA channel 3 at c48000c0, irq 36
    usbcore: registered new interface driver usbfs [subsys_initcall(usb_init)->usb_register(&usbfs_driver)->usb_register_driver]
    usbcore: registered new interface driver hub [subsys_initcall(usb_init)->usb_hub_init(&hub_driver)->usb_register_driver]
    usbcore: registered new device driver usb [subsys_initcall(usb_init)->usb_register_device_driver(&usb_generic_driver)]
    NET: Registered protocol family 2 [fs_initcall(inet_init)->sock_register]
    IP route cache hash table entries: 1024 (order: 0, 4096 bytes) [fs_initcall(inet_init)->ip_init->ip_rt_init ]
    TCP established hash table entries: 2048 (order: 2, 16384 bytes) [fs_initcall(inet_init)->ip_init->tcp_init]
    TCP bind hash table entries: 2048 (order: 1, 8192 bytes) [fs_initcall(inet_init)->ip_init->tcp_init]
    TCP: Hash tables configured (established 2048 bind 2048) [fs_initcall(inet_init)->ip_init->tcp_init]
    TCP reno registered [fs_initcall(inet_init)->ip_init->tcp_init->tcp_register_congestion_control]
    checking if image is initramfs...<5>it isn't (no cpio magic); looks like an initrd [rootfs_initcall(populate_rootfs)]
    Freeing initrd memory: 1024K [rootfs_initcall(populate_rootfs)->free_initrd->free_initrd_mem->free_area]
    NetWinder Floating Point Emulator V0.97 (extended precision) [module_init(fpe_init);]
    JFFS2 version 2.2. (NAND) 漏 2001-2006 Red Hat, Inc. [module_init(init_jffs2_fs);]
    io scheduler noop registered [module_init(noop_init)->elv_register]
    io scheduler anticipatory registered (default) [module_init(as_init)->elv_register]
    io scheduler deadline registered [module_init(deadline_init)->elv_register]
    io scheduler cfq registered [module_init(cfq_init)->elv_register]
    Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled [ module_init(serial8250_init)]
    s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440 [module_init(s3c24xx_serial_modinit)->s3c2440_serial_init->
    s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440 s3c2440_serial_probe->uart_add_one_port->
    s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440 uart_configure_port->uart_report_port]
    RAMDISK driver initialized: 2 RAM disks of 4096K size 1024 blocksize [module_init(rd_init);]
    loop: module loaded [module_init(loop_init);]
    S3C24XX NAND Driver, (c) 2004 Simtec Electronics [module_init(s3c2410_nand_init);]
    s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns [s3c2440_nand_probes->3c2410_nand_inithw]
    NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit) [ form above...->nand_scan_ident nand_get_flash_type]
    Scanning device for bad blocks [s3c24xx_nand_probe->nand_scan ->nand_scan_tail->chip->scan_bbt:..->create_bbt]
    Creating 4 MTD partitions on "NAND 64MiB 3,3V 8-bit": [s3c2410_nand_add_partition->add_mtd_partitions]
    0x00000000-0x00030000 : "Boot Agent"
    0x00030000-0x00200000 : "kernel"
    0x00200000-0x02000000 : "ramfs"
    0x02000000-0x04000000 : "extfs"
    ohci_hcd: 2006 August 04 USB 1.1 'Open' Host Controller (OHCI) Driver
    ohci_hcd: block sizes: ed 64 td 64
    s3c2410-ohci s3c2410-ohci: s3c2410_start_hc:
    s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
    s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
    s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
    s3c2410-ohci s3c2410-ohci: created debug files
    s3c2410-ohci s3c2410-ohci: OHCI controller state
    s3c2410-ohci s3c2410-ohci: OHCI 1.0, NO legacy support registers
    s3c2410-ohci s3c2410-ohci: control 0x083 HCFS=operational CBSR=3
    s3c2410-ohci s3c2410-ohci: cmdstatus 0x00000 SOC=0
    s3c2410-ohci s3c2410-ohci: intrstatus 0x00000004 SF
    s3c2410-ohci s3c2410-ohci: intrenable 0x8000005a MIE RHSC UE RD WDH
    s3c2410-ohci s3c2410-ohci: hcca frame #001e
    s3c2410-ohci s3c2410-ohci: roothub.a 02001202 POTPGT=2 NOCP NPS NDP=2(2)
    s3c2410-ohci s3c2410-ohci: roothub.b 00000000 PPCM=0000 DR=0000
    s3c2410-ohci s3c2410-ohci: roothub.status 00008000 DRWE
    s3c2410-ohci s3c2410-ohci: roothub.portstatus [0] 0x00000100 PPS
    s3c2410-ohci s3c2410-ohci: roothub.portstatus [1] 0x00000100 PPSu
    sb usb1: default language 0x0409
    usb usb1: uevent
    usb usb1: usb_probe_device
    usb usb1: configuration #1 chosen from 1 choice
    usb usb1: adding 1-0:1.0 (config #1, interface 0)
    usb 1-0:1.0: uevent
    hub 1-0:1.0: usb_probe_interface
    hub 1-0:1.0: usb_probe_interface - got id
    hub 1-0:1.0: USB hub found
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0xa006,0x2900,0x0000,c3c19a84,000f)
    hub 1-0:1.0: 2 ports detected
    hub 1-0:1.0: standalone hub
    hub 1-0:1.0: no power switching (usb 1.0)
    hub 1-0:1.0: no over-current protection
    hub 1-0:1.0: power on to power good time: 4ms
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0xa000,0x0000,0x0000,c3c19a40,0004)
    hub 1-0:1.0: local power source is good
    hub 1-0:1.0: trying to enable port power on non-switchable hub
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0x2303,0x0008,0x0001,c3c19a40,0000)
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0x2303,0x0008,0x0002,c3c19a40,0000)
    hub 1-0:1.0: state 7 ports 2 chg 0000 evt 0000
    usb usb1: new device strings: Mfr=3, Product=2, SerialNumber=1
    usb usb1: Product: S3C24XX OHCI
    usb usb1: Manufacturer: Linux 2.6.24.4 ohci_hcd
    usb usb1: SerialNumber: s3c24xx
    s3c2410_udc: debugfs dir creation failed -19
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0xa300,0x0000,0x0001,c3c6fe30,0004)
    s3c2410-ohci s3c2410-ohci: s3c2410_hub_control(c3c2b400,0xa300,0x0000,0x0002,c3c6fe30,0004)
    mice: PS/2 mouse device common for all mice [module_init(mousedev_init);]
    S3C24XX RTC, (c) 2004,2006 Simtec Electronics [module_init(s3c_rtc_init);]
    s3c2440-i2c s3c2440-i2c: slave address 0x10 [s3c2440_i2c_driver.s3c24xx_i2c_probe->s3c24xx_i2c_init]
    s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz [同上]
    s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter [s3c2440_i2c_driver.s3c24xx_i2c_probe]
    S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics [module_init(watchdog_init);]
    s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
    TCP cubic registered [module_init(cubictcp_register)->tcp_register_congestion_control]
    drivers/rtc/hctosys.c: unable to open rtc device (rtc0) [late_initcall(rtc_hctosys)]
    RAMDISK: Compressed image found at block 0 [kernel_init->prepare_namespace->initrd_load->rd_load_image->identify_ramdisk_image]
    VFS: Mounted root (ext2 filesystem). [kernel_init->prepare_namespace->mount_root->mount_block_root->do_mount_root]
    Freeing init memory: 108K
    selected clock c0239b70 (pclk) quot 26, calc 115740 /*以下内容为busybox产生*/
    selected clock c0239b70 (pclk) quot 26, calc 115740
    init started: BusyBox v1.10.1 (2008-04-19 15:27:01 CST)
    selected clock c0239b70 (pclk) quot 26, calc 115740
    starting pid 225, tty '': '/etc/init.d/rcS'
    Open ARM AKAE-www.linuxforum.net
    Start mdev...
    mount: mounting sysfs on /sys failed: Device or resource busy
    selected clock c0239b70 (pclk) quot 26, calc 115740
    starting pid 236, tty '/dev/console': '-/bin/sh '
    BusyBox v1.10.1 (2008-04-19 15:27:01 CST) built-in shell (msh)
    Enter 'help' for a list of built-in commands.

    --------------------------------------------------------------------------------

    18 .Uart devices register and driver select

    1.machine和cpu的检测与uart设备名的设置
    CPU S3C2440A (id 0x32440001) [setup_arch->paging_init->devicemaps_init->mdesc->smdk2410_map_io->s3c24xx_init_io]
    mdesc是SMDK2410,smdk2410_map_io->s3c24xx_init_io根据cpuid设置arm/plat-s3c24xx的全局变量cpu.然后mdk2410_map_io
    调用s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));通过(cpu->init_uarts)(cfg, no);注册cpu特的定的uart资源. cpu_ids在arch/arm/plat-s3c24xx/cpu.c中,其中2440a的uart初始化函数是:

    void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
    {
    s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
    }
    void __init s3c24xx_init_uartdevs(char *name,
    struct s3c24xx_uart_resources *res,
    struct s3c2410_uartcfg *cfg, int no)
    {
    struct platform_device *platdev;
    struct s3c2410_uartcfg *cfgptr = uart_cfgs;
    struct s3c24xx_uart_resources *resp;
    int uart;

    memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);

    for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
    platdev = s3c24xx_uart_src[cfgptr->hwport];

    resp = res + cfgptr->hwport;

    s3c24xx_uart_devs[uart] = platdev; /*uart的platform设备*/

    platdev->name = name; /*platform 设备名称初始化为 "s3c2440-uart" */
    platdev->resource = resp->resources;
    platdev->num_resources = resp->nr_resources;

    platdev->dev.platform_data = cfgptr;
    }

    nr_uarts = no;
    }
    然后arch_initcall(s3c_arch_init);-> platform_add_devices(s3c24xx_uart_devs, nr_uarts);注册设备到
    platform_bus_type.

    2.console 设备初始化

    selected clock c0239b70 (pclk) quot 26, calc 115740 [console_initcall(s3c24xx_serial_initconsole)->register_console->console.setup->s3

免费预约试听课