一、内核移植步骤



1, 修改顶层目录下的Makefile



ARCH            ?= $(SUBARCH)



CROSS_COMPILE   ?= $(CONFIG_CROSS_COMPILE:"%"=%)



修改为:



ARCH :=arm


CROSS_COMPILE :=/usr/local/arm/4.4.3/bin/arm-linux-

2, 修改机器码:要让bootload的机器码和内核的机器码一致(machine ID)

2、1 在u-boot代码(./board/samsung/smdk2416/smdk2416.c)中,赋值machine ID的代码如下:


gd->bd->bi_arch_number = MACH_TYPE;


这个宏的定义在:include/configs/smdk2416.h


  1. /*
  2.  * Architecture magic and machine type
  3.  */
  4. # define MACH_TYPE        1685


2、2 在linux内核(./arch/arm/mach-s3c2416/mach-smdk2416.c)中,代码是这样:


MACHINE_START( SMDK2416 , "SMDK2416")


这里SMDK2416就是machine ID的代号,那具体值是多少呢?~


这个宏的定义在arch/arm/include/asm/mach/arch.h



  1. /*
  2.  * Set of macros to define architecture features. This is built into
  3.  * a table by the linker.
  4.  */
  5. # define MACHINE_START( _type ,
  6. static const struct machine_desc __mach_desc_# # _type    /
  7.  __used                            /
  8.  __attribute__( ( __section__( ".arch.info.init" ) ) ) = {     /
  9.     
  10. .nr        = MACH_TYPE_##_type,
  11.     
  12. . name        = _name,

  13. # define MACHINE_END                /
  14. } ;


这个宏定义扩展之后的machine type 就成了 MACHINE_TYPE_SMDK2416。




MACHINE_TYPE_SMDK2416这个宏定义在include/generated/mach-types.h



 
# define MACH_TYPE_SMDK2416 1685



2、3 在arch/arm/tools/mach-types中


smdk2416 MACH_SMDK2416 SMDK2416


原来我们的machine ID是1685


所以只要这三个数值保持一样即可。。


如果没有uboot源码 ,从打印信息也可以看到参数,修改内核即可。



bootloader传递进来的值是多少呢?~



Error: unrecognized/unsupported machine ID (r1 = 0x00000695).



注意到没有? 0x695转换成10进制也就是1685





3, 拷贝配置文件



 这里用的是S3C2416的机子,拷贝2410的配置文件到内核的配置文件.config(这里面没有2416的配置文件)



 cp arch/arm/configs/s3c2410_defconfig   .config



4,内核配置


4、1配置内核之前,先修改有些地方的Kconfig吧,以支持我们2416的板子


4、1、1  linux-2.6.35\arch\arm\mach-s3c2416\kconfig中增加:

 config MACH_SMDK2416

        bool "SMDK2416"

        select CPU_S3C2416

        select S3C_DEV_FB

        select S3C_DEV_NAND  #add by ljf

        select S3C_DEV_USB_HOST  #add by ljf

        select S3C_DEV_SMDK #add by ljf

        select S3C_DEV_HSMMC

        select S3C_DEV_HSMMC1

        help

    Say Y here if you are using an SMDK2416

目的:linux-2.6.35\arch\arm\mach-s3c2416\makefile 文件:


    obj-$(CONFIG_S3C_DEV_USB_HOST)  += dev-usb.o

 等相应的宏打开

4、1、2


config MACH_SMDK

                bool

                default y #add by ljf

                help

              Common machine code for SMDK2410 and SMDK2440

目的:开linux-2.6.35\arch\arm\plat-s3c24xx\makefile 文件:CONFIG_MACH_SMDK宏打开

obj-$(CONFIG_MACH_SMDK)       += common-smdk.o   



这个是使针对makefile 文件宏控制做相应的更改的:

4、2 配置内核


 Kernel Features  --->   //使用EABI工具链这两项是必须选择的

[*] Use the ARM EABI to compile the kernel

[*]   Allow old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)

System Type  --->(选板子)


S3C2410 Machines  --->



[*] SMDK2410/A9M2410(只选择此项) ???


S3C2416 Machines  --->


[*] SMDK2416

5,编译内核

#make zImage

编译完后,会在 arch/arm/boot 下生成zImage内核镜像文件 
可以修改该目录下的 Makefile:  在第 57 行下面添加: 
@cp –f arch/arm/boot/zImage zImage 

@echo ` Kernel: $@ is ready`

下载到机子看看,内核起来了。到这里只是引导起来了。

6、内核分区,nandflash分区

6、1 修改:arch/arm/plat-s3c24xx/common-smdk.c 文件,在第 110 行:

/* NAND parititon from 2.4.18-swl5 */
 static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "2416_Boot",
.size =    0x00100000,
.offset .mask_flags= MTD_CAP_NANDFLASH,
},
[1] = {
.name = "2416_kernel",
.offset = 0x00100000,
.size =    0x00800000,.mask_flags= MTD_CAP_NANDFLASH,
}, 
[2] = { 

 
.name = "2416_kernel",
.offset = 0x00900000,
.size =    0x00300000,.mask_flags= MTD_CAP_NANDFLASH,
},
[3] = {
.name = "2416_rootfs",
.offset = 0x00c00000,
.size = MTDPART_OFS_APPEND,
}
 };

然后修改NandFlash的读写匹配时间,修改common-smdk.c文件的刚刚修改后的大概140行左右的
smdk_nand_info结构体,修改内容如下:

staticstructs3c2410_platform_nandsmdk_nand_info={
 .tacls =10,
 .twrph0 =25,
 .twrph1 =10,
 .nr_sets =ARRAY_SIZE(smdk_nand_sets),
 .sets =smdk_nand_sets,};

6、2 然后修改“drivers/mtd/nand/s3c2410.c”文件的842行的NAND_ECC_SOFT改为NAND_ECC_NONE
将原来的内容改为如下所示

} else {
chip->ecc.mode   = NAND_ECC_NONE; // NAND_ECC_SOFT
}
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;


6、3 配置内核,支持 NandFlash 

Device Drivers ---> 
      <*> Memory Technology Device (MTD) support ---> 
            [*]   MTD partitioning support 
            <*> NAND Device Support --->        [ ]     Samsung S3C NAND driver debug



6、4 修改arch/arm/mach-2416/s3c2416.c文件中:(不然nand驱动加载不了,启动信息没打印出nand分区信息)


 

void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no)
 {
               s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
               s3c_device_nand.name = "s3c2416-nand";这个与下面面的要对应更改为“s3c2440-nand”
 } 

  

Driver/mtd/nand/s3c2410.c文件中: 

static struct platform_device_id s3c24xx_driver_ids[] = { 

  { 

       .name         = "s3c2410-nand", 

       .driver_data  = TYPE_S3C2410, 

  }, { 

       .name         = "s3c2440-nand", 

       .driver_data  = TYPE_S3C2440, 

  }, { 

       .name         = "s3c2412-nand", 

       .driver_data  = TYPE_S3C2412, 

  }, { 

       .name         = "s3c6400-nand", 

       .driver_data  = TYPE_S3C2412, /* compatible with 2412 */ 

  }, 

  { }
};

6、5启动后若打印信息如下错误


S3C24XX NAND Driver, (c) 2004 Simtec Electronics
 s3c24xx-nand s3c2440-nand: Tacls=2, 14ns Twrph0=4 29ns, Twrph1=2 14ns
 s3c24xx-nand s3c2440-nand: NAND ECC disabled
 NAND device: Manufacturer ID: 0xec, Chip ID: 0xdc (Samsung NAND 512MiB 3,3V 8-bit)
 NAND_ECC_NONE selected by board driver. This is not recommended !!
 Scanning device for bad blocks
 Bad eraseblock 0 at 0x000000000000
 Bad eraseblock 5 at 0x000001400000
 Creating 3 MTD partitions on "NAND 512MiB 3,3V 8-bit":
 0x000000000000-0x000000900000 : "2416_Boot"
 mtd: partition "2416_Boot" doesn't end on an erase block -- force read-only
 0x000000900000-0x000000c00000 : "2416_kernel"
 mtd: partition "2416_kernel" doesn't start on an erase block boundary -- force read-only
 0x000000c00000-0x000020000000 : "2416_rootfs"




解决办法,在分区时加上如上的红色部分!!!



7、jffs文件系统

7.1

具体的打印信息:




/linuxrc.  Attempting defaults... 



 Kernel panic - not syncing: No init found.  Try passing init= option to kernel. See Linux Documentation/init.txt for guidance. 


解决办法:



首先是解读表面上的含义,那就是找不到可执行文件 linuxrc 或者说是执行不了 。于是回头去看打印的信息,

VFS: Mounted root (jffs2 filesystem) on device 31:3.
Freeing init memory: 132K可以看出文件系统有挂载上去,所以接下来就怀疑可能是文件系统出问题了。回头看文件系统:文件系统制作时用的交叉编译器和内核是一样的,而且在之前的内核2.6.21上面是正常跑起来的,根据这个我认为文件系统是没问题的,就怀疑是内核配置问题。然后在网上查一通,该支持额都配置了。还是不行:然后根据打印信息查找出是哪里打印出来的,在linux2.6.35/init/main.c     826行
/* This is a non __init function. Force it to be noinline otherwise gcc
  * makes it inline to init() and it becomes part of init.text section
  */
 static noinline int init_post(void)
__releases(kernel_lock)
 {
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();

current->signal->flags |= SIGNAL_UNKILLABLE;

if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}


/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s.  Attempting "
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");


panic("No init found.  Try passing init= option to kernel. "
.");
 }

由我们boot的启动参数可以看出execute_command值是/linuxrc,run_init_process(execute_command);这个函数如果可以执行那么就不会返回回来也就不会打印红色字体的信息了,这说明“run_init_process”这个函数执行有问题:我们来看看这个函数:

static void run_init_process(char *init_filename)
 {
argv_init[0] = init_filename;
kernel_execve(init_filename, argv_init, envp_init);
 }再去看函数“kernel_execve”:在arch/arm/kernel/sys_arm.c  
int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 {
struct pt_regs regs;
int ret;
memset(®s, 0, sizeof(struct pt_regs));
ret = do_execve((char *)filename, (char __user * __user *)argv,
(char __user * __user *)envp, ®s);
if (ret < 0)
goto out;

/*
* Save argc to the register structure for userspace.
*/
regs.ARM_r0 = ret;

/*
* We were successful.  We won't be returning to our caller, but
* instead to user space by manipulating the kernel stack.
*/
asm( "add r0, %0, %1\n\t"
"mov r1, %2\n\t"
"mov r2, %3\n\t"
"bl memmove\n\t" /* copy regs to top of stack */
"mov r8, #0\n\t" /* not a syscall */
"mov r9, %0\n\t" /* thread structure */
"mov sp, r0\n\t" /* reposition stack pointer */
"b ret_to_user"
:
: "r" (current_thread_info()),
 "Ir" (THREAD_START_SP - sizeof(regs)),
 "r" (®s),
 "Ir" (sizeof(regs))
: "r0", "r1", "r2", "r3", "ip", "lr", "memory");
  out:
return ret;
 }
 EXPORT_SYMBOL(kernel_execve);

问题应该就出在这里头,但是这里有汇编,这下我头大了。不知道有谁能帮我探索一下,感激不尽啊!!!