linux 3.4内核初始化,S3C2440移植linux3.4.2内核之内核框架介绍及简单修改
@[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 ?= arm
CROSS_COMPILE ?= arm-linux-
配置編譯cd arch/arm/configs //由于我們板子是arm板,進入該目錄
ls *2440* //找到有mini2440_defconfig、
ls *2410* //找到有s3c2410_defconfig
cd ../../..
make s3c2410_defconfig //配置2410, 更新.config配置文件
make uImage //編譯,生成uImage
cp arch/arm/boot/uImage /work/nfs_root/ //拷貝
cd /work/nfs_root/
mv uImage uImage_new
進入.config查看支持的CPUvi .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:140
recipe for target kernel/timeconst h failed make【1】:*** 【kernel/timeconst h】 Error 255
Makefile: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_new
bootm 32000000
如下圖所示,發現串口輸出亂碼:
設置機器ID
uboot傳遞進來的機器ID可以通過環境變量machid來設置
所以任意設置一個ID,這樣再次啟動內核時,內核識別不出來,就會打印出所有設備對應的機器ID。下面開始測試機器ID是否正確,進入uboot,輸入:set machid 33333
tftp 32000000 uImage
bootm 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 uImage
cp uImage /work/nfs_root/ uImage_new
進入uboot,輸入:set machid 16a
nfs 32000000 192.168.1.30:/work/nfs_root/uImage_new
bootm 32000000
如遇到排版錯亂的問題,可以通過以下鏈接訪問我的CSDN。
**CSDN:[CSDN搜索“嵌入式與Linux那些事”]
總結
以上是生活随笔為你收集整理的linux 3.4内核初始化,S3C2440移植linux3.4.2内核之内核框架介绍及简单修改的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux远程开机windows,从Li
- 下一篇: 现在八卦变成什么了,有质量的贴在哪里?