一、环境搭建
源码包下载:git clone https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.10.8.tar.gz
或者直接去kernel.org上面进行下载。
交叉编译工具链制作:
这个已经在u-boot移植中已经做过了:http://www.cnblogs.com/kele-dad/p/6910040.html
二、内核启动过程
2.1 Windows 和 Linux 系统的启动区别
由bootloader确定启动哪块单板。
2.2 修改makefile
下面的行注释掉:
修改ARCH:
修改交叉编译工具链:
2.3 选择默认配置
找到默认配置:
进入arm架构中:
可以看到我们的架构中有 mini2440的架构,同时也有s3c2410的配置文件。
进入内核根目录,配置成2410:
打开.config 文件
查看CPU,可以看到有2440的CPU:
同时也支持 mini2440 的单板:
2.4 编译
执行:make uImage
进行编译:
编译提示错误,那是因为没有安装u-boot 依赖包。
提示要安装新包
再执行编译:
编译成功。
2.5 烧写
通过nfs进行烧写,nfs配置如文档:http://www.cnblogs.com/kele-dad/p/7082765.html
启动内核:bootm 32000000
看一下打印信息,有条错误,无法识别机器ID。下面打印出来了很多机器ID。
现在我们要根据我们的机器ID 去u-boot 源码中看一下启动内核的代码了。
进入Cmd_bootm.c (common),搜索bootm,找到下面这行代码:
上面代码调用了 do_bootm 函数,进入函数中查看:
1 U_BOOT_CMD 2 do_bootm 3 do_bootm_subcommand 4 do_bootm_subcommand 5 do_bootm_states 6 boot_os_fn *boot_fn; 7 bootm_start 8 bootm_find_os 9 bootm_find_other 10 bootm_load_os 11 boot_fn = bootm_os_get_boot_func(images->os.os); 12 do_bootm_states
在do_bootm_states 中有一个结构体,boot_os_fn:
1 static boot_os_fn *boot_os[] = { 2 [IH_OS_U_BOOT] = do_bootm_standalone, 3 #ifdef CONFIG_BOOTM_LINUX 4 [IH_OS_LINUX] = do_bootm_linux, 5 #endif 6 #ifdef CONFIG_BOOTM_NETBSD 7 [IH_OS_NETBSD] = do_bootm_netbsd, 8 #endif 9 #ifdef CONFIG_LYNXKDI 10 [IH_OS_LYNXOS] = do_bootm_lynxkdi, 11 #endif 12 #ifdef CONFIG_BOOTM_RTEMS 13 [IH_OS_RTEMS] = do_bootm_rtems, 14 #endif 15 #if defined(CONFIG_BOOTM_OSE) 16 [IH_OS_OSE] = do_bootm_ose, 17 #endif 18 #if defined(CONFIG_BOOTM_PLAN9) 19 [IH_OS_PLAN9] = do_bootm_plan9, 20 #endif 21 #if defined(CONFIG_BOOTM_VXWORKS) && \ 22 (defined(CONFIG_PPC) || defined(CONFIG_ARM)) 23 [IH_OS_VXWORKS] = do_bootm_vxworks, 24 #endif 25 #if defined(CONFIG_CMD_ELF) 26 [IH_OS_QNX] = do_bootm_qnxelf, 27 #endif 28 #ifdef CONFIG_INTEGRITY 29 [IH_OS_INTEGRITY] = do_bootm_integrity, 30 #endif 31 #ifdef CONFIG_BOOTM_OPENRTOS 32 [IH_OS_OPENRTOS] = do_bootm_openrtos, 33 #endif 34 };
在此结构体中调用的是 do_bootm_linux 函数,进入查看 Bootm.c (arch\arm\lib)
1 int do_bootm_linux(int flag, int argc, char * const argv[], 2 bootm_headers_t *images) 3 { 4 /* No need for those on ARM */ 5 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 6 return -1; 7 8 if (flag & BOOTM_STATE_OS_PREP) { 9 boot_prep_linux(images); 10 return 0; 11 } 12 13 if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { 14 boot_jump_linux(images, flag); 15 return 0; 16 } 17 18 boot_prep_linux(images); 19 boot_jump_linux(images, flag); 20 return 0; 21 }
在最后一句中执行 boot_jump_linux 函数:
1 /* Subcommand: GO */ 2 static void boot_jump_linux(bootm_headers_t *images, int flag) 3 { 4 unsigned long machid = gd->bd->bi_arch_number; 5 char *s; 6 void (*kernel_entry)(int zero, int arch, uint params); 7 unsigned long r2; 8 int fake = (flag & BOOTM_STATE_OS_FAKE_GO); 9 10 kernel_entry = (void (*)(int, int, uint))images->ep; 11 12 s = getenv("machid"); 13 if (s) { 14 if (strict_strtoul(s, 16, &machid) < 0) { 15 debug("strict_strtoul failed!\n"); 16 return; 17 } 18 printf("Using machid 0x%lx from environment\n", machid); 19 } 20 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 21 announce_and_cleanup(fake); 22 23 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 24 r2 = (unsigned long)images->ft_addr; 25 else 26 r2 = gd->bd->bi_boot_params; 27 28 if (!fake) { 29 kernel_entry(0, machid, r2); 30 } 31 }
从环境变量中获取mach_id ,然后进入 kernel。如果没有从环境变量获取,就采用默认值,此函数的第一句就是默认值。看看默认值是多少。
machid = gd->bd->bi_arch_number;
在Jz2440.c (board\samsung\jz2440) 中 设置了默认ID:
1 int board_init(void) 2 { 3 /* arch number of JZ2440 board */ 4 gd->bd->bi_arch_number = MACH_TYPE_JZ2440; 5 6 /* adress of boot parameters */ 7 gd->bd->bi_boot_params = 0x30000100; 8 9 icache_enable(); 10 dcache_enable(); 11 12 return 0; 13 }
同时在Board_f.c (common) 的 setup_machine中也有设置ID:
1 static int setup_machine(void) 2 { 3 #ifdef CONFIG_MACH_TYPE 4 gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ 5 #endif 6 return 0; 7 }
CONFIG_MACH_TYPE 这个宏我们没有设置。
那么我们的上一个设置ID的函数是有效的。
在Mach-types.h (arch\arm\include\asm) 中设置的ID为194。
然后在内核处,进入arch/arm/s3c24x0/ 目录,里面有很多我们的支持s3c24x0的板子,进入smdk2440的单板文件 mach-smdk2440.c:
MACHINE_START(S3C2440, "SMDK2440") /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ .atag_offset = 0x100, .init_irq = s3c2440_init_irq, .map_io = smdk2440_map_io, .init_machine = smdk2440_machine_init, .init_time = smdk2440_init_time, MACHINE_END
在MACHINE_START中,就是根据mchine ID找到单板文件的。MACHINE_START的定义如下:
展开后, .nr = MACH_TYPE_S3C2440,查找一下这个宏。
generated 是临时生成的文件目录。可以看一下 mach-types.h:
这是smdk2440的机器码
这是mini2440的机器码
可以对照我们的u-boot打印看出来:
16进制转换成10进制就可以算出来了。
根据以上的内容,我们可以在u-boot 中设置我们的 mach_id 的环境变量来启动内核,或者我们可以直接修改 u-boot 的默认ID值和这里的机器ID匹配即可。
修改成mini2440的机器ID。直接修改u-boot源码:
把mini2440改成如下:
jz2440改成如下:
这两个定义的机器码进行了对调而已。
在 include/configs/jz2440.h 中设置启动参数,要加上波特率设置,否则会有乱码。mini2440的内核文件中设置的波特率为115200,smdk2440的为16M。
然后编译烧写u-boot。
进入u-boot 记得 print查看一下环境变量,如果 波特率没有改变过来 就重新设置一下:
保存一下。然后烧入内核
启动内核:
已经有打印信息了。
来源:https://www.cnblogs.com/kele-dad/p/7082682.html