@[TOC]

uboot启动内核剖析

  进入cmd_bootm.c,找到对应的bootm命令对应的do_bootm():

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]){boot_os_fn *boot_fn;             //boot_fn是个数组函数 ... ..boot_fn(0, argc, argv, &images); //调用数组函数 ... ...}

  boot_os_fn是个typedef型,如下图所示:

  因为定义了宏CONFIG_BOOTM_LINUX,最终会跳转到do_bootm ->do_bootm_linux()
  代码如下所示:

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images){         /* No need for those on ARM */         if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)                   return -1;         if (flag & BOOTM_STATE_OS_PREP) {                   boot_prep_linux(images);                   return 0;         }         if (flag & BOOTM_STATE_OS_GO) {                   boot_jump_linux(images);                   return 0;         }          boot_prep_linux(images);      //该函数会将各个tag参数保留在指定地位,比方:内存tag、bootargs环境变量tag、串口tag等         boot_jump_linux(images);      //该函数会跳转到内核起始地址         return 0;}

  最终跳转到do_bootm ->do_bootm_linux-> boot_jump_linux()

static void boot_jump_linux(bootm_headers_t *images){         unsigned long machid = gd->bd->bi_arch_number;     //获取机器ID         char *s;         void (*kernel_entry)(int zero, int arch, uint params);         unsigned long r2;         kernel_entry = (void (*)(int, int, uint))images->ep;  //设置kernel_entry()的地址为0x30000000         s = getenv("machid");                     //判断环境变量machid是否设置,若设置则应用环境变量里的值            if (s) {                          strict_strtoul(s, 16, &machid);      //从新获取机器ID                   printf("Using machid 0x%lx from environment\n", machid);  //应用环境变量的machid         }     ... ...        r2 = gd->bd->bi_boot_params;     //获取tag参数地址, gd->bd->bi_boot_params在setup_start_tag()函数里被设置         kernel_entry(0, machid, r2);     //跳转到0x30000000,r0=0,r1=机器ID,r2=tag参数地址}

   下面的machid默认值为MACH_TYPE_SMDK2410(也就是193),咱们也能够在环境变量里设置machid变量
最终,便跳到内核执行代码,步骤如下所示:
  1)依据R1(机器ID),来判断内核是否反对该机器,若反对则初始化机器相干函数
  2)解析TAG参数,初始化串口,设置内存等
  3)挂载根文件系统,并执行应用程序

简略配置内核

  批改Makefile,批改配置

tar xjf linux-3.4.2.tar.bz2 cd linux-3.4.2/vi Makefile 


  改为

ARCH            ?= armCROSS_COMPILE   ?= arm-linux-

  配置编译

cd arch/arm/configs                //因为咱们板子是arm板,进入该目录ls  *2440*                            //找到有mini2440_defconfig、ls  *2410*                            //找到有s3c2410_defconfigcd ../../..make s3c2410_defconfig                //配置2410, 更新.config配置文件 make uImage                          //编译,生成uImagecp arch/arm/boot/uImage /work/nfs_root/           //拷贝cd /work/nfs_root/ mv uImage uImage_new


  进入.config查看反对的CPU

vi .config


  如上图所示,有咱们的2440

编译内核

make uImage

  报错如下

Can't use 'defined(@array)'(Maybe you should just omit the defined? )at kernel/timeconst pl line 373/root/working/Hi3520D SDK V2.0.3.0/osdrv/kernel/linux-30y/kernel/Makefile:140recipe for target kernel/timeconst h failed make【1】:*** 【kernel/timeconst h】 Error 255Makefile:945:recipe for target kernel ' failed【kernel】 Error 2

解决办法
  将 kernel/timeconst.pl中第373行的 defined0去掉只留下@val就能够了

vim kernel/timeconst.pl +373

  进入uboot烧写

nfs 32000000 192.168.2.106:/work/nfs_root/uImage_newbootm 32000000  

  如下图所示,发现串口输入乱码:

设置机器ID

  uboot传递进来的机器ID能够通过环境变量machid来设置
  所以任意设置一个ID,这样再次启动内核时,内核辨认不进去,就会打印出所有设施对应的机器ID。上面开始测试机器ID是否正确,进入uboot,输出:

set machid 33333tftp 32000000 uImagebootm 32000000

  如下图所示,因为内核不反对这个机器ID,所以打印出内核能反对的ID表:

  ID所对应的文件为arch/arm/mach-s3c24xx/Mach-smdk2440.c

  MACHINE_START为一个构造体,依据不同的机器ID找到对应的MACHINE_START,调用初始化函数。
  因为咱们板子是2440,所以测试7cf(mini2440)以及16a(smdk2440)这两个机器ID,是否反对咱们开发板。
  然而仍旧乱码,可能是波特率设置不正确。从新设置下环境变量的波特率

set bootargs root=/dev/mtdblock3 console=ttySAC0,115200 

  再次烧写启动,发现7cf(mini2440)这个ID,有串口输入失常。上面看下16a(smdk2440)为什么串口乱码,进入mach-smdk2440.c( 位arch/arm/mach-s3c24xx)找到问题出在smdk2440_map_io():

static void __init smdk2440_map_io(void){         s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));         s3c24xx_init_clocks(16934400);             //初始化时钟clock         s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));}

批改晶振

  因为咱们板子上的晶振是12Mhz,而mdk2440_map_io()里,初始化的时钟是基于16934400hz的晶振。所以将:

s3c24xx_init_clocks(16934400);             //初始化时钟clock

  改为:

s3c24xx_init_clocks(12000000);             //初始化时钟clock

  而后从新编译uImage:

make  s3c2410_defconfig             //将mach-s3c2440.c配置进内核make  uImagecp uImage /work/nfs_root/ uImage_new

  进入uboot,输出:

set machid 16anfs 32000000 192.168.1.30:/work/nfs_root/uImage_newbootm 32000000

  启动内核打印失常。

  下一节S3C2440移植linux3.4.2内核之批改分区以及制作根文件系统
咱们将批改分区和制作根文件系统。

如遇到排版错乱的问题,能够通过以下链接拜访我的CSDN。

**CSDN:[CSDN搜寻“嵌入式与Linux那些事”]