2009年10月6日 星期二

U-Boot的移植



U-Boot Practically Porting Guide



Author: Aaron Wong aaronwong@engineer.com




U-Boot的移植之(二)進階篇:從源代碼看系統啟動過程



為什麼要分析源代碼?分析優秀的源代碼本身就是一個學習的過程,也是進行深入研究的必經之路。不過在此我們的主要目的並非要研究U-boot或Bootloader技術本身,而僅僅是為了成功的並且恰當的將U-Boot移植到我們的開發板上。只有結合源代碼瞭解了U-boot的系統引導過程,才能在移植和調試過程中保持清晰的思路,才能在碰到困難和問題時從根本上加以解決。



在動手分析之前,至少應該對U-Boot的源代碼結構有基本的瞭解,很多參考書都有這方面的介紹,華清遠見的《嵌入式Linux系統開發技術詳解——基於ARM》的講解就比較清晰。



本文以lubbock開發板為例,以系統啟動的流程為線索進行縱向分析:後續的移植工作也將以此開發板為模板。Lubbock使用PXA255處理器。



首先要找到程序入口點。從board/lubbock/u-boot.lds可以發現,u-boot的程序入口為_start,在cpu/pxa/start.o當中。因此首先要分析start.S程序,U-Boot中所有的PXA系列的處理器都從這裡開始執行第一條語句。






.globl _start




_start: b reset




ldr pc, _undefined_instruction




ldr pc, _software_interrupt




ldr pc, _prefetch_abort




ldr pc, _data_abort




ldr pc, _not_used




ldr pc, _irq




ldr pc, _fiq




0x0地址開始是ARM異常向量表,學過ARM體系結構與編程的都明白,非常簡單,不多廢話。一上電的第一條指令是跳轉到reset復位處理程序:






reset:




/* 進入SVC模式 */




#ifndef CONFIG_SKIP_LOWLEVEL_INIT




bl cpu_init_crit /* we do sys-critical inits */




#endif




#ifndef CONFIG_SKIP_RELOCATE_UBOOT




relocate:




......




一般不要定義CONFIG_SKIP_LOWLEVEL_INIT,因此,接下來跳轉到cpu_init_crit處開始執行:






cpu_init_crit:




/* 屏蔽所有中斷 */




/* 設置時鍾源,關閉除FFUART,SRAM,SDRAM,FLASH以外的外設時鍾 */




......




#ifdef CFG_CPUSPEED




ldr r0, CC_BASE /* 時鍾控制寄存器基址 */




ldr r1, cpuspeed




/* cpuspeed: .word CFG_CPUSPEED */




str r1, [r0, #CCCR]




mov r0, #2




mcr p14, 0, r0, c6, c0, 0









setspeed_done:




#endif /* CFG_CPUSPEED */




/* 跳轉到lowlevel_init,這裡ip即r12,用作暫存寄存器 */




mov ip, lr




bl lowlevel_init




mov lr, ip




/* Memory interfaces are working. Disable MMU and enable I-cache. */




ldr r0, =0x2001




......




/* 關閉MMU,使能I-Cache(可選) */




mov pc, lr /* 這裡是從cpu_init_crit返回到relocate標號 */









可見,在cpu_init_crit中的主要工作是設置時鍾,配置處理器主頻(這時CPU的工作頻率還沒有改變),調用lowlevel_init函數進行底層初始化(包括調整處理器工作頻率、系統總線頻率、存儲器時鍾頻率以及存儲系統的初始化等工作),隨後關閉MMU並使能I-Cache,再返回。



lowlevel_init函數在board/lubbock/lowlevel_init.S中定義,其流程都是按照PXA27X的開發手冊來的,所以不再贅述。僅指出,其中的寄存器在include/asm-arm/arch-pxa/pxa-regs.h頭文件中定義,寄存器初始化值在include/configs/lubbock.h中定義。另外,在後面的實際移植工作中,由於目標板XSBASE270使用的PXA270處理器,可使用adsvix開發板的lowlevel_init.S文件(lubbock中沒有開啟turbo模式)。



接著程序的執行線索進行分析。從cpu_init_crit返回後就開始relocate(重定位),即將U-boot從FLASH存儲器搬運到SDRAM中TEXT_BASE開始的存儲空間(TEXT_BASE在board/lubbock/config.mk中定義),並初始化堆棧(清零.bss段),以在SDRAM中開始進入到Bootloader stage 2的C程序入口。Relocate部分開始的代碼如下:






/* 之前已定義的部分變量有:




_TEXT_BASE: .word TEXT_BASE




_armboot_start: .word _start




_bss_start: .word __bss_start




_bss_end: .word _end */




relocate: /* relocate U-Boot to RAM */




adr r0, _start /* r0 <- current position of code */




ldr r1, _TEXT_BASE /* test if we run from flash or RAM */




cmp r0, r1 /* don't reloc during debug */




beq stack_setup









ldr r2, _armboot_start /* 讀入_start到r2 */




ldr r3, _bss_start /* 讀入__bss_start到r3 */




sub r2, r3, r2 /* r2 <- size of armboot */




add r2, r0, r2 /* r2 <- source end address */









copy_loop:




ldmia r0!, {r3-r10} /* copy from source address [r0] */




stmia r1!, {r3-r10} /* copy to target address [r1] */




cmp r0, r2 /* until source end addreee [r2] */




ble copy_loop









/* Set up the stack */




stack_setup:




ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */




sub r0, r0, #CFG_MALLOC_LEN /* malloc area */




sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */




#ifdef CONFIG_USE_IRQ




sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)




#endif




sub sp, r0, #12 /* leave 3 words for abort-stack */









clear_bss:




ldr r0, _bss_start /* find start of bss segment */




ldr r1, _bss_end /* stop here */




mov r2, #0x00000000 /* clear */









clbss_l:str r2, [r0] /* clear loop... */




add r0, r0, #4




cmp r0, r1




ble clbss_l









ldr pc, _start_armboot









_start_armboot: .word start_armboot




這是很經典的一段代碼,相信學習凡是過ARM編程的,都分析過這段代碼,所以也不再贅述。之所以列出這段代碼,一是為了找到C程序入口start_armboot,二是為了給出U-Boot的一個存儲器映射圖:







這個圖可以幫助我們更好地理解後續的C語言代碼以及U-Boot對內存的分配與使用情況。



接下來進入到Bootloader Stage 2即C語言代碼部分,入口是start_armboot,對應的源文件是lib_arm/board.c,這一文件對所有的ARM處理器都是通用的,因此在移植的時候不用修改。相關源代碼如下:






DECLARE_GLOBAL_DATA_PTR;




/* 在include/asm-arm/global_data.h中定義的一個全局寄存器變量的聲明:




* #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")




* 用於存放全局數據結構體gd_t的地址。




*/




void start_armboot (void)




{




init_fnc_t **init_fnc_ptr;




char *s;




#ifndef CFG_NO_FLASH




ulong size;




#endif




#if defined(CONFIG_VFD) || defined(CONFIG_LCD)




/* 本次移植暫不配置VFD和LCD,後面也將不考慮的部分略去 */




/* 初始化全局數據結構體指針gd */




gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));




....../* memset在lib_generic/string.c中定義*/




memset ((void*)gd, 0, sizeof (gd_t)); /*用0填充全局數據表*gd */




gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));




memset (gd->bd, 0, sizeof (bd_t)); /*用0填充(初始化) *gd->bd */









monitor_flash_len = _bss_start - _armboot_start;









for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {




if ((*init_fnc_ptr)() != 0) {




hang (); /* 打印錯誤信息並死鎖 */




}




}









#ifndef CFG_NO_FLASH




/* configure available FLASH banks */




size = flash_init (); /* drivers/cfi_flash.c或自定義 */




display_flash_config (size);




#endif /* CFG_NO_FLASH */









/*armboot_start is defined in the board-specific linker script*/




mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);




......




/* initialize environment */




env_relocate ();









/* IP Address */




gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");




/* MAC Address */




{




int i;




ulong reg;




char *s, *e;




char tmp[64];









i = getenv_r ("ethaddr", tmp, sizeof (tmp));




s = (i > 0) ? tmp : NULL;









for (reg = 0; reg < 6; ++reg) {




gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;




if (s)




s = (*e) ? e + 1 : e;




}




}









devices_init (); /* get the devices list going. */




.......




jumptable_init ();




console_init_r (); /* fully init console as a device */




enable_interrupts (); /* enable exceptions */









/* Perform network card initialisation if necessary */




#if defined(CONFIG_DRIVER_SMC91111)| |defined (CONFIG_DRIVER_LAN91C96)




if (getenv ("ethaddr"))




smc_set_mac_addr(gd->bd->bi_enetaddr);




#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */









/* Initialize from environment */




if ((s = getenv ("loadaddr")) != NULL) {




load_addr = simple_strtoul (s, NULL, 16);




}









#if defined(CONFIG_CMD_NET)




if ((s = getenv ("bootfile")) != NULL)




copy_filename (BootFile, s, sizeof (BootFile));




#endif




#ifdef BOARD_LATE_INIT




board_late_init ();




#endif




......




/*main_loop() can return to retry autoboot, if so just run it again.*/




for (;;) {




main_loop ();




}




}




gd_t是全局數據表類型,在include/asm-arm/global_data.h中定義如下:






/*




Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t)




*/




typedef struct global_data {




bd_t *bd;




unsigned long flags;




unsigned long baudrate;




unsigned long have_console; /* serial_init() was called */




unsigned long reloc_off; /* Relocation Offset */




unsigned long env_addr; /* Address of Environment struct */




unsigned long env_valid; /*Checksum of Environment valid?*/




unsigned long fb_base; /* base address of frame buffer */




.......




void **jt; /* jump table */




} gd_t;




其中,bd_t在include/asm-arm/u-boot.h中定義如下:






typedef struct bd_info {




int bi_baudrate; /* serial console baudrate */




unsigned long bi_ip_addr; /* IP Address */




unsigned char bi_enetaddr[6]; /* Ethernet adress */




struct environment_s *bi_env;




ulong bi_arch_number; /* unique id for this board */




ulong bi_boot_params; /* where this board expects params*/




struct /* RAM configuration */




{




ulong start;




ulong size;




}bi_dram[CONFIG_NR_DRAM_BANKS];




} bd_t;




jt是函數數組指針,隨後將在jumptable_init()函數中初始化。



從lib_arm/board.c的源碼不難分析出系統的啟動流程:首先初始化全局數據表,然後順序執行函數指針數組init_sequence中的一系列初始化函數——由其在本文件中的相關定義可得知初始化流程:






typedef int (init_fnc_t) (void);




init_fnc_t *init_sequence[] = {




cpu_init, /* basic cpu dependent setup -- cpu/pxa/cpu.c */




board_init, /* basic board setup --board/lubbock/lubbock.c */




interrupt_init, /* set up exceptions -- cpu/pxa/interrupts.c */




env_init, /* initialize environment -- common/env_flash.c */




init_baudrate, /* initialze baudrate settings--lib_arm/board.c */




serial_init, /* serial communications setup--cpu/pxa/serial.c */




console_init_f, /* stage 1 init of console -- common/console.c */




display_banner, /* say that we are here -- lib_arm/board.c */




#if defined(CONFIG_DISPLAY_BOARDINFO)




checkboard, /* display board info */




#endif




dram_init, /* configure available RAM banks --board/lubbock/lubbock.c */




display_dram_config, /* lib_arm/board.c */




NULL,




};




在執行這個函數序列的過程中,任何一個函數異常返回都會導致u-boot「死鎖」或說「掛起」在hang()函數的死循環當中。



若一切順利,接下來就調用flash_init()函數初始化CFI FLASH(針對NOR型閃存而言),該函數在drivers/cfi_flash.c中定義,不過,只有在目標板頭文件中」#define CFG_FLASH_CFI_DRIVER」之後該驅動才會被編譯;在lubbock的u-boot實現當中,include/configs/lubbock.h中沒有定義CFG_FLASH_CFI_DRIVER,而是在board/lubbock/ flash.c中實現了自己的FLASH驅動,包括flash_init()在內。在移植U-Boot時,可以根據實際情況選擇使用U-Boot自帶的FLASH驅動還是自己編寫新的驅動。如果配置了NAND閃存,還會對其進行初始化;筆者的XSABSE270板沒有銲接NAND FLASH,故對此不作討論。



接下來調用env_relocate()函數初始化環境變量,該函數在common/env_common.c文件中定義。在同一文件中可以發現還定義了一個字符數組default_environment[],用於描述缺省的環境變量,這些都要在include/configs/lubbock.h頭文件中進行設置,包括啟動命令CONFIG_BOOTCOMMAND,波特率CONFIG_BAUDRATE,IP地址CONFIG_IPADDR等等。



然後是獲取自設置的目標板的網絡地址,包括IP地址和MAC地址。



再然後是調用common/devices.c中定義的devices_init()函數來創建設備列表,並初始化相應的設備,主要是」stdin」,」stdout」,」stderr」以及自定義的設備如I2C,LCD等。這些相關代碼是與平台無關的,因此從移植的角度考慮,不必作細緻的研究與分析。



接著調用common/exports.c中定義的jumptable_init()函數,初始化全局數據表中的跳轉表gd->jt,跳轉表是一個函數指針數組,定義了u-boot中基本的常用的函數庫;而gd->jt是這個函數指針數組的首指針。部分代碼如下:






void jumptable_init (void) {




int i;




gd->jt = (void **) malloc (XF_MAX * sizeof (void *));




for (i = 0; i < XF_MAX; i++)




gd->jt[i] = (void *) dummy;




gd->jt[XF_get_version] = (void *) get_version;




gd->jt[XF_malloc] = (void *) malloc;




gd->jt[XF_free] = (void *) free;




gd->jt[XF_getenv] = (void *) getenv;




gd->jt[XF_setenv] = (void *) setenv;




......




}




上面的XF_get_version, XF_malloc, XF_free等在include/exports.h的枚舉變量中定義,因此,實際上是作為」Label式整型序號」使用,即XF_get_version=1, XF_malloc=2, XF_free=3 ...,相關代碼如下:






enum { /* include/exports.h */




#define EXPORT_FUNC(x) XF_ ## x ,




#include <_exports.h>




#undef EXPORT_FUNC




XF_MAX



};




EXPORT_FUNC(get_version)




EXPORT_FUNC(getc)




EXPORT_FUNC(tstc)




EXPORT_FUNC(putc)




EXPORT_FUNC(puts)




EXPORT_FUNC(printf)




......... /* include/_exports.h */




由於這些也是平台無關的代碼,因此在移植過程中也不必深究。



然後是調用common/console.c中定義的函數console_init_r()初始化串口控制台,這同樣是平台無關的代碼,所以不必關心。



這時U-Boot的基本功能已經初始化完畢,便可開中斷,並進行附加功能的配置與初始化,包括網卡驅動配置,目標板使用LAN91C1111網卡,對應SMC91111網卡驅動,可以根據需要配置其他的網卡驅動如CS8900等,這些都在include/configs/lubbock.h中定義。



然後是調用board/lubbock/lubbock.c中定義的board_late_init()函數進行板級的後期初始化,實際上是配置stdout和stderr的硬件設備。相關源代碼如下:






int board_late_init(void)




{




setenv("stdout", "serial");




setenv("stderr", "serial");




return 0;




}








最後需要注意的一個很重要的文件是lib_arm/armlinux.c,它實現的功能包括設置內核啟動參數,並負責將這些參數傳遞給內核,最後跳轉到Linux內核入口函數,將控制權交給內核。



具體傳遞哪些參數,是通過在include/configs/lubbock.c中指定條件編譯選項來控制的,對應於lib_arm/armlinux.c中的部分源代碼形式如下:






#if defined (CONFIG_SETUP_MEMORY_TAGS) || \




defined (CONFIG_CMDLINE_TAG) || \




defined (CONFIG_INITRD_TAG) || \




defined (CONFIG_SERIAL_TAG) || \




defined (CONFIG_REVISION_TAG)




static void setup_start_tag (bd_t *bd);









# ifdef CONFIG_SETUP_MEMORY_TAGS




static void setup_memory_tags (bd_t *bd);




# endif




static void setup_commandline_tag (bd_t *bd, char *commandline);









# ifdef CONFIG_INITRD_TAG




static void setup_initrd_tag (bd_t *bd, ulong initrd_start,




ulong initrd_end);




# endif




static void setup_end_tag (bd_t *bd);




static struct tag *params;




#endif




......




void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],




ulong addr, ulong *len_ptr, int verify)




{




......




void (*theKernel)(int zero, int arch, uint params);




......




#ifdef CONFIG_CMDLINE_TAG




char *commandline = getenv ("bootargs");




#endif




theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);




......




theKernel (0, bd->bi_arch_number, bd->bi_boot_params);




}




關於這個參數列表中各個參數的定義及含義,以及參數列表的初始化過程,可以參考Booting ARM Linux一文。內核是如何找到這個參數列表在內存中的位置,以接收這些參數的呢?實際上,參數列表(tag list)在內存中的起始地址會保存在通用寄存器

Kernel 2.4 & 2.6 編譯差異

Kernel 2.4       

1.編譯設定:

# make menuconfig

2.編譯核心:

# make dep

# make bzImage

3.編譯模組並安裝:

# make modules

# make modules_install




kernel 2.6


1.編譯設定:

# make menuconfig

2.編譯核心與模組:

# make

3.安裝:

# make modules_install install




Kernel 2.6 模組編譯

kernel 2.6 的模組「模組化」程度相當高,因此在 kernel 2.6 環境下編譯模組時,是以 sub-module 的觀念來實施,與 kernel 2.4 的獨立編譯觀念不同。首先,舉我們的 debug card 範例來說明編譯 kernel 2.6 模組的方式;接著再說明安裝 kernel 2.6 模組的方法。
1. 先撰寫編譯模組的 Makefile 如下:

    obj-m := card.o

    KDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)

    default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

2. 編譯:

    # make

編譯後可以得到 card.ko,這才是真正的 kernel 2.6 模組;kernel 2.6 模組的副檔名為 "*.ko"。

3. 將 card.ko 複制到模組目錄下:

    # cp card.ko /lib/modules/`uname -r`/kernel/drivers/

4. 重新產生模組的 "dependency descriptions":

    # depmod -a

5. 安裝模組:

    # insmod ./card.ko

或是:

    # modprobe card

同樣是利用 insmod 或 modprobe 指令將 card.ko 安裝至系統即可。

2009年9月7日 星期一

vivi Memory 常數




/* Flash */
#define FLASH_BASE                       ROM_BASE0    /* 0x3000 0000 */
#define FLASH_SIZE                       SZ_32M
#define FLASH_UNCACHED_BASE       0x10000000    /* to mapping flash memory */
#define FLASH_BUSWIDTH               4
/* ROM */
#define VIVI_ROM_BASE                  0x00000000
#define VIVI_PRIV_ROM_BASE           0x01FC0000














/* Porocessor memory map */
#define ROM_BASE0          0x00000000      /* base address of rom bank 0 */
#define ROM_BASE1          0x08000000      /* base address of rom bank 1 */
#define DRAM_BASE0        0x30000000      /* base address of dram bank 0 */
#define DRAM_BASE1        0x38000000        /* base address of dram bank 1 */




#define DRAM_BASE          DRAM_BASE0   /* 0x3000 0000*/
#define DRAM_SIZE          SZ_64M      

#define MTD_PART_SIZE                       SZ_16K   /* 16k=0x40000 */
#define MTD_PART_OFFSET                   0x00000000
#define PARAMETER_TLB_SIZE               SZ_16K   /* 16k=0x4000 */
#define PARAMETER_TLB_OFFSET           0x00004000
#define LINUX_CMD_SIZE                      SZ_16K  
#define LINUX_CMD_OFFSET                  0x00008000
#define VIVI_PRIV_SIZE                        (MTD_PART_SIZE + PARAMETER_TLB_SIZE + LINUX_CMD_SIZE) 




/* 16k+16k+16k=48k=*/


/* RAM */
#define VIVI_RAM_SIZE                   SZ_1M 
#define VIVI_RAM_BASE                  (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE) 




/* 0x3000 0000 + 64M - 1M = 0x33ff ffff - 1M = 0x33ef ffff*/




#define HEAP_SIZE                         SZ_1M
#define HEAP_BASE                        (VIVI_RAM_BASE - HEAP_SIZE)




/* 0x33ef ffff - 1M = 0x33df ffff*/




#define MMU_TABLE_SIZE                SZ_16K
#define MMU_TABLE_BASE               (HEAP_BASE - MMU_TABLE_SIZE)




/* 0x33df ffff - 16k = 0x33df bfff*/




#define VIVI_PRIV_RAM_BASE           (MMU_TABLE_BASE - VIVI_PRIV_SIZE)




/* 0x33df bfff - 48k= 0x33de ffff*/




#define STACK_SIZE                       SZ_32K
#define STACK_BASE                      (VIVI_PRIV_RAM_BASE - STACK_SIZE)




/* 0x33de ffff - 32k = 0x33de 7fff*/




#define RAM_SIZE                          (STACK_BASE - DRAM_BASE)




/* 0x33de 7fff - 0x3000 000 = 0x3de 7fff = 64M - 1M - 1M - 16K-48K-16K - 32k= 61M + 912K*/




#define RAM_BASE                          DRAM_BASE 




/* 0x3000 0000 */


2009年9月6日 星期日

移植 linux-2.6.26 內核





主機:
ubuntu 8.04 (linux-2.6.24-19)
gcc-4.2

目標板:
s3c2440

交叉編譯器:
請參考
《ubuntu 開發環境設置 For embedded system 》
 
要移植的內核版本:
linux-2.6.26

文件系統:
cramfs
---------------------------------------------------------------------------------------------------
準備知識:

Linux支持多種平台架構。在原始碼的arch目錄下,已經將各種支援的平台架構的原始碼分門別類。為了配置方便,在各種平台架構的目錄下,一般都配有一個名為configs的目錄。其中,放著許多已經初步配置好的defconfig文件。通過這些defconfig文件,加快了我們編譯內核的速度。
比如我所用的是一個arm架構的s3c2440板,那我就可以從arch/arm/configs/中找到s3c2410_defconfig,這是目前最相似2440的一個設定文件了。使用:
$ make s3c2410_defconfig
或
$ cp arch/arm/configs/s3c2410_defconfig ./.config

執行上面命令後,將會在原始碼目錄下產生.config配置文件。執行

$ make menuconfig
或
$ make xconfig


可以進一步配置內核。最後執行

$ make zImage


生成我們所需的燒錄文件

內核編譯基本命令:

make mrproper --- 清理全部文件,包括.config和一些備份文件, 或
make clean --- 清理生成文件,但會保留.config和一些模塊文件。

make defconfig --- 產生包含全部預設選項的.config文件。這裡用make s3c2410_defconfig替代
make oldconfig --- 在舊的.config基礎上生成新的.config。如果只想在原來內核配置的基礎上修改一些小地方,會省去不少麻煩

make config --- 基於文本的最為傳統的配置界面,不推薦使用
make menuconfig --- 基於文本選單的配置界面,字符終端下推薦使用
make xconfig --- 基於圖形窗口模式的配置界面,Xwindow下推薦使用
  
   目的都是生成一個.config文件,這三個命令中,make xconfig的界面最為友好,如果你可以使用Xwindow,你就用這個好了,這個比較方便,也好設置。如果你不能使用Xwindow,那麼就使用 make menuconfig好了。界面雖然比上面一個差點,總比make config的要好多了。

make --- 預設編譯。
make bzImage --- 編譯生成壓縮的核心二進制檔案,也會用make zImage替代

---------------------------------------------------------------------------------------------------
參考資料:
《 Linux2.6.22.2內核移植方法 》
《 移植內核2.6.24.4到S3C2440 》
《  對於Kernel panic - ……出錯的一點總結! 》

---------------------------------------------------------------------------------------------------
移植linux-2.6.26內核(假設已下載linux-2.6.26.tar.bz2)

1. 解壓源代碼

$ tar jxvf linux-2.6.26.tar.bz2

$ cd linux-2.6.26


2. 更改Makefile

#ARCH        ?= $(SUBARCH)

#CROSS_COMPILE    ?=
ARCH        ?= arm
CROSS_COMPILE    ?= /usr/local/arm/4.0.3/arm-linux-gnu/bin/arm-linux-gnu-


3. 產生預設配置

$ make s3c2410_defconfig


4. 增加devfs文件系統支持
linux2.6.26已經去掉devfs,為了內核支援devfs以及在啟動時並在/sbin/init運行之前能自動掛載/dev為devfs文件系統,修改fs的Kconfig文件。
linux-2.6.26/fs/Kconfig

修改的內容:
找到menu "Pseudo filesystems"
增加底下的程式:
  
config DEVFS_FS

    bool "/dev file system support (OBSOLETE)"
    depends on EXPERIMENTAL
    help
      This is support for devfs, a virtual file system (like /proc) which
      provides the file system interface to device drivers, normally found
      in /dev. Devfs does not depend on major and minor number
      allocations. Device drivers register entries in /dev which then
      appear automatically, which means that the system administrator does
      not have to create character and block special device files in the
      /dev directory using the mknod command (or MAKEDEV script) anymore.

      This is work in progress. If you want to use this, you *must* read
      the material in , especially
      the file README there.

      Note that devfs no longer manages /dev/pts! If you are using UNIX98
      ptys, you will also need to mount the /dev/pts filesystem (devpts).

      Note that devfs has been obsoleted by udev,
      <http://www.kernel.org/pub/linux/utils/kernel/hotplug/>.
      It has been stripped down to a bare minimum and is only provided for
      legacy installations that use its naming scheme which is
      unfortunately different from the names normal Linux installations
      use.

      If unsure, say N.

config DEVFS_MOUNT
    bool "Automatically mount at boot"
    depends on DEVFS_FS
    help
      This option appears if you have CONFIG_DEVFS_FS enabled. Setting
      this to 'Y' will make the kernel automatically mount devfs onto /dev
      when the system is booted, before the init thread is started.
      You can override this with the "devfs=nomount" boot option.

      If unsure, say N.

config DEVFS_DEBUG
    bool "Debug devfs"
    depends on DEVFS_FS
    help
      If you say Y here, then the /dev file system code will generate
      debugging messages. See the file
      for more details.

      If unsure, say N.


5. 修改時鐘頻率( 可解決印出訊息有亂碼問題 )
文件:arch/arm/mach-s3c2440/mach-smdk2440.c

    /*s3c24xx_init_clocks(16934400);*/

    s3c24xx_init_clocks(12000000);

6. 修改MTD分區
文件: arch/arm/plat-s3c24xx/common-smdk.c

/* fix mtd partition to be same with bootloader */

/* a flash all in 64M bit size have been devided into 4 partition: */
/*   1. boot : offset is 0 and size is 192k */
/*   2. kernel : offset is 0x30000 and size is 1856k */
/*   3. rootfs : offset is 0x200000 and size is 30M */
/*   4. ext-fs1 : offset is 0x2000000 and size is 32M */
static struct mtd_partition smdk_default_nand_part[] = {
    [0] = {
        .name    = "boot", /* default is "Boot Agent", by qspy */
        .size    = SZ_64K*3,  /* default is SZ_16K, qspy fix it to 192K*/
        .offset    = 0,
    },
    [1] = {
        .name    = "kernel", /* default is "S3C2410 flash partition 1", by qspy */
        .offset = SZ_64K*3,/* default is 0, by qspy */
        .size    = SZ_64K*29,/* default is SZ_2M, qspy fix it to 1856K*/
    },
    [2] = {
        .name    = "rootfs",/* default is "S3C2410 flash partition 2", by qspy */
        .offset = SZ_2M,/* default is SZ_4M, by qspy */
        .size    = SZ_1M*30,/* default is SZ_4M, qspy fix it to 30M*/
    },
    [3] = {
        .name    = "ext-fs1",/* default is "S3C2410 flash partition 2", by qspy */
        .offset    = SZ_32M,/* default is SZ_8M, by qspy */
        .size    = SZ_32M,/* default is SZ_2M, qspy fix it to 30M*/
    },
   };

  
7. 關閉ECC檢查
文件:drivers/mtd/nand/s3c2410.c
函數:s3c2410_nand_init_chip
        /*chip->ecc.mode        = NAND_ECC_SOFT; */

        chip->ecc.mode    = NAND_ECC_NONE;

8. 設定內核

$ make xconfig

其中有幾項一定要修改的,分別是:

a. 啟動
|---Boot options

|    |---Default kernel command string: [root=/dev/mtdblock2 rootfstype=cramfs init=/linuxrc console=ttySAC1,115200 devfs=mount mem=64]

分析:
/dev/mtdblock2 : 表示MTD分區的第2個分區存儲根文件系統
rootfstype=cramfs : 分區是cramfs類型,這項不加應該關係不大
init=/linuxrc : 啟動的首個腳本就是根目錄下的linuxrc
console=ttySAC1,115200 : 使用串口1作為串口輸出,波特率設置為115200; 現在已經放棄了以前使用ttyS0的寫法
devfs=mount : 在/sbin/init運行之前能自動掛載/dev為devfs文件系統
mem=64 : 記憶體大小為64M

b. 增加devfs文件系統支持

|---File systems

|    |---Pseudo filesystems
|    |      |---/dev file system support
|    |      |      |---Automatically mount at boot
|    |      |      |---Debug devfs

 
這幾項都是必選的

c. CPU及系統類型

|---System Type

|    |---S3C2410 Machines
|    |      |---SMDK2410/A9M2410

支持2440時,這一項也是必選的,否則會編譯不過

-----------------------------------------------------
遇到的問題:

1. 啟動時亂碼
信息:

Nand flash status = c0

Set boot params = root=/dev/mtdblock2 init=/linuxrc load_ramdisk=0 console=ttySAC1,115200 mem=65536K devfs=mount display=shp480
Load Kernel...
8??腳c?泉''D?G#溰 `納 { 悃\'榌

解決:時鐘問題,更改時鐘頻率為12M即可

2. 文件系統cramfs掛載失敗

IP route cache hash table entries: 1024 (order: 0, 4096 bytes)

TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
NET: Registered protocol family 1
NetWinder Floating Point Emulator V0.97 (double precision)
msgmni has been set to 120
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
brd: module loaded
usbcore: registered new interface driver ub
dm9000 Ethernet Driver, V1.30
Linux video capture interface: v2.00
NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c $Revision: 1.41 $
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=1, 10ns Twrph0=4 40ns, Twrph1=1 10ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
s3c2410_nand_update_chip: chip c3d7d4bc: 9
Scanning device for bad blocks
Bad eraseblock 357 at 0x00594000
Bad eraseblock 3335 at 0x0341c000
Bad eraseblock 3995 at 0x03e6c000
Creating 4 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00030000 : "boot"
0x00030000-0x00200000 : "kernel"
0x00200000-0x02000000 : "rootfs"
0x02000000-0x04000000 : "ext-fs1"
usbmon: debugfs is not available
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
Registered led device: led4
Registered led device: led5
Registered led device: led6
Registered led device: led7
TCP cubic registered
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
end_request: I/O error, dev mtdblock2, sector 2
EXT2-fs: unable to read superblock
end_request: I/O error, dev mtdblock2, sector 0
Buffer I/O error on device mtdblock2, logical block 0
end_request: I/O error, dev mtdblock2, sector 0
Buffer I/O error on device mtdblock2, logical block 0
end_request: I/O error, dev mtdblock2, sector 8
Buffer I/O error on device mtdblock2, logical block 1
end_request: I/O error, dev mtdblock2, sector 8
Buffer I/O error on device mtdblock2, logical block 1
end_request: I/O error, dev mtdblock2, sector 16
Buffer I/O error on device mtdblock2, logical block 2
end_request: I/O error, dev mtdblock2, sector 16
Buffer I/O error on device mtdblock2, logical block 2
end_request: I/O error, dev mtdblock2, sector 24
Buffer I/O error on device mtdblock2, logical block 3
end_request: I/O error, dev mtdblock2, sector 24
Buffer I/O error on device mtdblock2, logical block 3
end_request: I/O error, dev mtdblock2, sector 0
FAT: unable to read boot sector
VFS: Cannot open root device "mtdblock2" or unknown-block(31,2)
Please append a correct "root=" boot option; here are the available partitions:
1f00        192 mtdblock0 (driver?)
1f01       1856 mtdblock1 (driver?)
1f02      30720 mtdblock2 (driver?)
1f03      32768 mtdblock3 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,2)

問題可能:
a。MTD分區與bootloader不匹配
b。沒有 devfs文件系統支持
c。ECC校驗沒有關閉

3. /linuxrc初始化失敗
Linux video capture interface: v2.00

NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c $Revision: 1.41 $
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=1, 10ns Twrph0=4 40ns, Twrph1=1 10ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
s3c2410_nand_update_chip: chip c3d704bc: 9
NAND_ECC_NONE selected by board driver. This is not recommended !!
Scanning device for bad blocks
Bad eraseblock 357 at 0x00594000
Bad eraseblock 3335 at 0x0341c000
Bad eraseblock 3995 at 0x03e6c000
Creating 4 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00030000 : "boot"
0x00030000-0x00200000 : "kernel"
0x00200000-0x02000000 : "rootfs"
0x02000000-0x04000000 : "ext-fs1"
usbmon: debugfs is not available
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
Registered led device: led4
Registered led device: led5
Registered led device: led6
Registered led device: led7
TCP cubic registered
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
VFS: Mounted root (cramfs filesystem) readonly.
Freeing init memory: 124K
cramfs: bad compressed blocksize 989432407
cramfs: bad compressed blocksize 4274059297
Failed to execute /linuxrc.  Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

問題可能:
a。 "Default kernel command string"設置有誤,比如啟動分區指定不對
b。 可能是文件系統有問題