天天看點

S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

目錄

  • uboot啟動核心分析
  • 簡單配置核心
  • 編譯核心
  • 設定機器ID
  • 修改晶振

  進入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型,如下圖所示:

S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  由于定義了宏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      
S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  改為

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      
S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  進入.config檢視支援的CPU

vi .config      
S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  如上圖所示,有我們的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      

  如下圖所示,發現序列槽輸出亂碼:

S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  uboot傳遞進來的機器ID可以通過環境變量machid來設定

  是以任意設定一個ID,這樣再次啟動核心時,核心識别不出來,就會列印出所有裝置對應的機器ID。下面開始測試機器ID是否正确,進入uboot,輸入:

set machid 33333
tftp 32000000 uImage
bootm 32000000      

  如下圖所示,由于核心不支援這個機器ID,是以列印出核心能支援的ID表:

S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  ID所對應的檔案為arch/arm/mach-s3c24xx/Mach-smdk2440.c

S3C2440移植linux3.4.2核心之核心架構介紹及簡單修改

  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      
set machid 16a
nfs 32000000 192.168.1.30:/work/nfs_root/uImage_new
bootm 32000000