linux4.10.8 內核移植(一)---環境搭建及適配單板。


一、環境搭建

  源碼包下載: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查看一下環境變量,如果 波特率沒有改變過來 就重新設置一下:

  

  保存一下。然后燒入內核

   

  啟動內核:

  

  已經有打印信息了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM