Linux3.4.0 Yaffs2文件系统移植-支持Android4.0


本文章主要针对FS100,S5PC100的Android4.0.4 Yaffs2文件系统移植过程,对于类似Android系统或类似Linux内核(版本高于2.6.35)有参考意义。

本文分两部分:

  1. Nandflash驱动移植
  2. Yaffs2文件系统移植

一、Nandflash驱动移植

由于内核里面没有S5PC100的Nandflash驱动,所以,我们将Nandflash的驱动文件拷贝到内核目录中:

将s3c_nand.c拷贝到:drivers/mtd/nand/中(s3c_nand.c放到了空间共享里了:http://download.csdn.net/detail/mr_raptor/4848511)。

Nand驱动修改位置:

1. 添加Nand物理地址

@arch/arm/mach-s5pc100/include/mach/map.h

添加如下内容:

// MichaelTang add for Nandflash start
/* NAND flash controller */
#define S5PC1XX_PA_NAND         (0xE7200000)
#define S5PC1XX_SZ_NAND         SZ_1M
// MichaelTang add for Nandflash end ----

2. 添加一个新的头文件:

@arch/arm/mach-s5pc100/include/mach/nand.h

#ifndef __MACH_NAND_H
#define __MACH_NAND_H
#include <linux/mtd/partitions.h>
struct s3c_nand_mtd_info {
        uint chip_nr;
        uint mtd_part_nr;
        struct mtd_partition *partition;
};
#endif

3. 修改寄存器头文件

@arch/arm/plat-samsung/include/plat/regs-nand.h

在regs-nand.h中添加如下宏:

// MichaelTang add for nand reg start
/* for s3c_nand.c */
#define S3C_NFCONF              S3C2410_NFREG(0x00)
#define S3C_NFCONT              S3C2410_NFREG(0x04)
#define S3C_NFCMMD              S3C2410_NFREG(0x08)
#define S3C_NFADDR              S3C2410_NFREG(0x0c)
#define S3C_NFDATA8             S3C2410_NFREG(0x10)
#define S3C_NFDATA              S3C2410_NFREG(0x10)
#define S3C_NFMECCDATA0         S3C2410_NFREG(0x14)
#define S3C_NFMECCDATA1         S3C2410_NFREG(0x18)
#define S3C_NFSECCDATA          S3C2410_NFREG(0x1c)
#define S3C_NFSBLK              S3C2410_NFREG(0x20)
#define S3C_NFEBLK              S3C2410_NFREG(0x24)
#define S3C_NFSTAT              S3C2410_NFREG(0x28)
#define S3C_NFMECCERR0          S3C2410_NFREG(0x2c)
#define S3C_NFMECCERR1          S3C2410_NFREG(0x30)
#define S3C_NFMECC0             S3C2410_NFREG(0x34)
#define S3C_NFMECC1             S3C2410_NFREG(0x38)
#define S3C_NFSECC              S3C2410_NFREG(0x3c)
#define S3C_NFMLCBITPT          S3C2410_NFREG(0x40)
#define S3C_NF8ECCERR0          S3C2410_NFREG(0x44) 
#define S3C_NF8ECCERR1          S3C2410_NFREG(0x48)
#define S3C_NF8ECCERR2          S3C2410_NFREG(0x4C)           
#define S3C_NFM8ECC0            S3C2410_NFREG(0x50)         
#define S3C_NFM8ECC1            S3C2410_NFREG(0x54)        
#define S3C_NFM8ECC2            S3C2410_NFREG(0x58)       
#define S3C_NFM8ECC3            S3C2410_NFREG(0x5C)      
#define S3C_NFMLC8BITPT0        S3C2410_NFREG(0x60)     
#define S3C_NFMLC8BITPT1        S3C2410_NFREG(0x64)  

#define S3C_NFCONF_NANDBOOT     (1<<31)
#define S3C_NFCONF_ECCCLKCON    (1<<30)
#define S3C_NFCONF_ECC_MLC      (1<<24)
#define S3C_NFCONF_ECC_1BIT     (0<<23)
#define S3C_NFCONF_ECC_4BIT     (2<<23)
#define S3C_NFCONF_ECC_8BIT     (1<<23)
#define S3C_NFCONF_TACLS(x)     ((x)<<12)
#define S3C_NFCONF_TWRPH0(x)    ((x)<<8)
#define S3C_NFCONF_TWRPH1(x)    ((x)<<4)
#define S3C_NFCONF_ADVFLASH     (1<<3)
#define S3C_NFCONF_PAGESIZE     (1<<2)
#define S3C_NFCONF_ADDRCYCLE    (1<<1)
#define S3C_NFCONF_BUSWIDTH     (1<<0)

#define S3C_NFCONT_ECC_ENC      (1<<18)
#define S3C_NFCONT_LOCKTGHT     (1<<17)
#define S3C_NFCONT_LOCKSOFT     (1<<16)
#define S3C_NFCONT_MECCLOCK     (1<<7)
#define S3C_NFCONT_SECCLOCK     (1<<6)
#define S3C_NFCONT_INITMECC     (1<<5)
#define S3C_NFCONT_INITSECC     (1<<4)
#define S3C_NFCONT_nFCE1        (1<<2)
#define S3C_NFCONT_nFCE0        (1<<1)
#define S3C_NFCONT_INITECC      (S3C_NFCONT_INITSECC | S3C_NFCONT_INITMECC)

#define S3C_NFSTAT_ECCENCDONE   (1<<7)
#define S3C_NFSTAT_ECCDECDONE   (1<<6)
#define S3C_NFSTAT_ILEGL_ACC    (1<<5)
#define S3C_NFSTAT_RnB_CHANGE   (1<<4)
#define S3C_NFSTAT_nFCE1        (1<<3)
#define S3C_NFSTAT_nFCE0        (1<<2)
#define S3C_NFSTAT_Res1         (1<<1)
#define S3C_NFSTAT_READY     (1<<0)
#define S3C_NFSTAT_CLEAR        ((1<<7) |(1<<6) |(1<<5) |(1<<4))

#define S3C_NFECCERR0_ECCBUSY   (1<<31)
// MichaelTang add for nand reg end

4. 修改平台机器代码初始化代码

@arch/arm/mach-s5pc100/mach-smdkc100.c 

添加如下内容:

// MichaelTang add for Nand
#include <linux/mtd/partitions.h>
#include <mach/nand.h>
...
/* NAND Controller */
static struct resource s5pc_nand_resource[] = {
        [0] = {
                .start = S5PC1XX_PA_NAND,
                .end   = S5PC1XX_PA_NAND + S5PC1XX_SZ_NAND - 1,
                .flags = IORESOURCE_MEM,
        }
};

struct platform_device s5pc_device_nand = {
        .name             = "s5pc100-nand",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s5pc_nand_resource),
        .resource         = s5pc_nand_resource,
};
struct mtd_partition s3c_partition_info[] = {
        {
                .name           = "bootloader",
                .offset         = 0,          /* for bootloader */
                .size           = SZ_1M,
                //.mask_flags     = MTD_CAP_NANDFLASH,
        },
        {
                .name           = "kernel",
                .offset         = MTDPART_OFS_APPEND,
                .size           = (4*SZ_1M),
                //.mask_flags   = MTD_CAP_NANDFLASH,
        },
        {
                .name           = "rootfs",
                .offset         = MTDPART_OFS_APPEND,
                .size           = MTDPART_SIZ_FULL,
        },
};

struct s3c_nand_mtd_info s3c_nand_mtd_part_info = {
        .chip_nr = 1,
        .mtd_part_nr = ARRAY_SIZE(s3c_partition_info),
        .partition = s3c_partition_info,
};

static struct platform_device *smdkc100_devices[] __initdata = {
....
        // Michaeltang add
        &s5pc_device_nand,
....

static void __init smdkc100_machine_init(void)
{
....
        //MichaelTang add for Nand
        s5pc_device_nand.dev.platform_data = &s3c_nand_mtd_part_info;
....
5. 由于新添加了驱动文件,要在menuconfig中添加编译项,并且让修改Makefile来编译驱动文件。

@drivers/mtd/nand/Kconfig

添加Kconfig的编译项

config MTD_NAND_S3C
        tristate "NAND Flash support for S3C SoC"
        depends on ARCH_S5PC100 && MTD_NAND
        help
          This enables the NAND flash controller on the S3C.


          No board specfic support is done by this driver, each board
          must advertise a platform_device for the driver to attach.


config MTD_NAND_S3C_HWECC
        bool "S3C NAND Hardware ECC"
        depends on MTD_NAND_S3C
        help
          Enable the use of the S3C's internal ECC generator when
          using NAND. Early versions of the chip have had problems with
          incorrect ECC generation, and if using these, the default of
          software ECC is preferable.

          If you lay down a device with the hardware ECC, then you will
          currently not be able to switch to software, as there is no
          implementation for ECC method used by the S3C

6. 添加驱动编译依赖文件

@drivers/mtd/nand/Makefile

# MichaelTang add for nand start
obj-$(CONFIG_MTD_NAND_S3C)              += s3c_nand.o
# MichaelTang add for nand end

7. 执行make menuconfig,将新添加的Nandflash驱动及mtd支持编译到内核中。

选择Kernel编译项:

Device Drivers  --->
<*> Memory Technology Device (MTD) support
    <*>   Caching block device access to MTD devices
	注:用于支持MTD块设备
    <*>   NAND Device Support  --->
         <*>   NAND Flash support for S3C SoC
         [*]     S3C NAND Hardware ECC
	注:选择新添加的Nand设备驱动,选择ECC硬件校验


二、Yaffs2文件系统移植

我们的Android文件系统使用YAFFS2文件系统格式,选择对应的支持项:

File systems  --->
    [*] Miscellaneous filesystems  --->
      <*>   YAFFS2 file system support

      注:默认Linux内核里不支持YAFFS2文件系统,我们可以从yaffs的官方网站上去下载其源码,然后给你的内核打上补丁即可:

http://www.yaffs.net/download-yaffs-using-git

保存退出,执行make zImage。


常见问题:

问题1:

fs/yaffs2/yaffs_vfs.c: In function 'yaffs_fill_inode_from_obj':
fs/yaffs2/yaffs_vfs.c:1333: error: assignment of read-only member 'i_nlink'
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_unlink':
fs/yaffs2/yaffs_vfs.c:1747: error: decrement of read-only member 'i_nlink'
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_link':
fs/yaffs2/yaffs_vfs.c:1782: error: assignment of read-only member 'i_nlink'
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_rename':
fs/yaffs2/yaffs_vfs.c:1901: error: decrement of read-only member 'i_nlink'

提示错误,说给只读的成员i_nlink赋值,出错代码如下:

inode->i_nlink = yaffs_get_obj_link_count(obj);

查看inode定义在 include/linux/fs.h

......
    /*
     * Filesystems may only read i_nlink directly.  They shall use the
     * following functions for modification:
     *
     *    (set|clear|inc|drop)_nlink
     *    inode_(inc|dec)_link_count
     */
    union {
        const unsigned int i_nlink;
        unsigned int __i_nlink;
    };
......

通过上面的注释可知,我们可以直接读取i_nlink成员,但是不能对其进行修改操作,必须使用(set|clear|inc|drop)_nlink进行修改操作。

于是,将出错的代码处改为:

// MichaelTang modify
set_nlink(inode, yaffs_get_obj_link_count(obj));
//inode->i_nlink = yaffs_get_obj_link_count(obj);


问题2:

fs/yaffs2/yaffs_vfs.c:440: warning: initialization from incompatible pointer type 
fs/yaffs2/yaffs_vfs.c:445: warning: initialization from incompatible pointer type 
fs/yaffs2/yaffs_vfs.c:447: warning: initialization from incompatible pointer type 
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_mtd_put_super': 
fs/yaffs2/yaffs_vfs.c:2514: error: 'struct mtd_info' has no member named 'sync' 
fs/yaffs2/yaffs_vfs.c:2515: error: 'struct mtd_info' has no member named 'sync' 
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_internal_read_super': 
fs/yaffs2/yaffs_vfs.c:2702: error: 'struct mtd_info' has no member named 'erase' 
fs/yaffs2/yaffs_vfs.c:2703: error: 'struct mtd_info' has no member named 'read' 
fs/yaffs2/yaffs_vfs.c:2704: error: 'struct mtd_info' has no member named 'write' 
fs/yaffs2/yaffs_vfs.c:2705: error: 'struct mtd_info' has no member named 'read_oob' 
fs/yaffs2/yaffs_vfs.c:2706: error: 'struct mtd_info' has no member named 'write_oob' 
fs/yaffs2/yaffs_vfs.c:2707: error: 'struct mtd_info' has no member named 'block_isbad' 
fs/yaffs2/yaffs_vfs.c:2708: error: 'struct mtd_info' has no member named 'block_markbad' 
fs/yaffs2/yaffs_vfs.c:2732: error: 'struct mtd_info' has no member named 'erase' 
fs/yaffs2/yaffs_vfs.c:2733: error: 'struct mtd_info' has no member named 'block_isbad' 
fs/yaffs2/yaffs_vfs.c:2734: error: 'struct mtd_info' has no member named 'block_markbad' 
fs/yaffs2/yaffs_vfs.c:2734: error: 'struct mtd_info' has no member named 'read' 
fs/yaffs2/yaffs_vfs.c:2734: error: 'struct mtd_info' has no member named 'write' 
fs/yaffs2/yaffs_vfs.c:2736: error: 'struct mtd_info' has no member named 'read_oob' 
fs/yaffs2/yaffs_vfs.c:2736: error: 'struct mtd_info' has no member named 'write_oob' 
fs/yaffs2/yaffs_vfs.c:2757: error: 'struct mtd_info' has no member named 'erase' 
fs/yaffs2/yaffs_vfs.c:2757: error: 'struct mtd_info' has no member named 'read' 
fs/yaffs2/yaffs_vfs.c:2757: error: 'struct mtd_info' has no member named 'write' 
fs/yaffs2/yaffs_vfs.c:2759: error: 'struct mtd_info' has no member named 'read_oob' 
fs/yaffs2/yaffs_vfs.c:2759: error: 'struct mtd_info' has no member named 'write_oob' 
make[2]: *** [fs/yaffs2/yaffs_vfs.o] 错误 1 
make[1]: *** [fs/yaffs2] 错误 2 
make: *** [fs] 错误 2

根据错误信息,mtd_info结构体成员没有对应的:sync、erase、read、write等成员,找到struct mtd_info的定义:

@include/linux/mtd/mtd.h

struct mtd_info {
......


         /*
          * Do not call via these pointers, use corresponding mtd_*()
          * wrappers instead.
          */
	// 不要直接通过函数指针的文件调用这些函数,尽量使用对应的mtd_xxx()封装函数替代,
	// 如,要调用_sync,则使用其对应的封装函数:mtd_sync().
         int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
         int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, void **virt, resource_size_t *phys);
         int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
         unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
                                              unsigned long len,
                                              unsigned long offset,
                                              unsigned long flags);
         int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
                       size_t *retlen, u_char *buf);
         int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
                        size_t *retlen, const u_char *buf);
         int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
                              size_t *retlen, const u_char *buf);
         int (*_read_oob) (struct mtd_info *mtd, loff_t from,
                           struct mtd_oob_ops *ops);
         int (*_write_oob) (struct mtd_info *mtd, loff_t to,
                            struct mtd_oob_ops *ops);
         int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
                                     size_t len);
         int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
                                     size_t len, size_t *retlen, u_char *buf);
         int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
                                     size_t len);
         int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                                     size_t len, size_t *retlen, u_char *buf);
         int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
                                      size_t len, size_t *retlen, u_char *buf);
         int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                                     size_t len);
         int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
                         unsigned long count, loff_t to, size_t *retlen);
         void (*_sync) (struct mtd_info *mtd);
         int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
         int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
         int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
         int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
         int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
         int (*_suspend) (struct mtd_info *mtd);
         void (*_resume) (struct mtd_info *mtd);
......

 static inline void mtd_sync(struct mtd_info *mtd)
 {
         if (mtd->_sync)
                 mtd->_sync(mtd);
 }

......

由代码及注释可知,mtd_info中成员发生改变是为了让大家使用新的mtd_xxx()封装函数而不使用函数指针。我们有两种方式修改代码:

    1>.直接将mtd->sync()的调用,改成mtd->_sync(),这种方式修改简单,也没有问题,但是和新mtd_info的初衷相悖。

    2>.将mtd->sync()改成mtd_sync()

修改位置:

@fs/yaffs2/yaffs_vfs.c

@fs/yaffs2/yaffs_mtdif.c 

@fs/yaffs2/yaffs_mtdif1.c 

@fs/yaffs2/yaffs_mtdif2.c


问题3:

fs/yaffs2/yaffs_vfs.c:2967: error: implicit declaration of function 'd_alloc_root' 
fs/yaffs2/yaffs_vfs.c:2967: warning: assignment makes pointer from integer without a cast 

make[2]: *** [fs/yaffs2/yaffs_vfs.o] 错误 1 
make[1]: *** [fs/yaffs2] 错误 1 
make: *** [fs] 错误 1

根据错误信息知,找不到d_alloc_root方法,原因是新的linux内核fs/dcache.c里使用d_make_root函数,所以直接将函数名换下即可。

@fs/yaffs2/yaffs_vfs.c

// MichaelTang modify
root = d_make_root(inode);
//root = d_alloc_root(inode);
yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: d_make_root done");
//yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: d_alloc_root done");

问题4:

fs/yaffs2/yaffs_vfs.c:2392: error: implicit declaration of function 'get_sb_bdev'
fs/yaffs2/yaffs_vfs.c: At top level:
fs/yaffs2/yaffs_vfs.c:2399: error: unknown field 'get_sb' specified in initializer
fs/yaffs2/yaffs_vfs.c:2399: warning: initialization makes integer from pointer without a cast
fs/yaffs2/yaffs_vfs.c:2423: error: unknown field 'get_sb' specified in initializer

错误信息提示,找不到get_sb_bdev和get_sb。

分析2.6.35前的代码可知,这两个函数是旧内核提供的函数,新内核使用了mount_bdev和mount函数,所以我们做如下代码修改:

第一处,针对yaffs的修改:

// MichaelTang modify start
#if 0
static int yaffs_read_super(struct file_system_type *fs,
                int flags, const char *dev_name,
                void *data, struct vfsmount *mnt)
{


        return get_sb_bdev(fs, flags, dev_name, data,
                        yaffs_internal_read_super_mtd, mnt);
}


static struct file_system_type yaffs_fs_type = {
        .owner = THIS_MODULE,
        .name = "yaffs",
        .get_sb = yaffs_read_super,
        .kill_sb = kill_block_super,
        .fs_flags = FS_REQUIRES_DEV,
};
#else
static struct super_block *yaffs_read_super(struct file_system_type *fs,
                int flags, const char *dev_name,
                void *data)
{
        return mount_bdev(fs, flags, dev_name, data,
                        yaffs_internal_read_super_mtd);
}
static struct file_system_type yaffs_fs_type = {
        .owner = THIS_MODULE,
        .name = "yaffs",
        //.get_sb = yaffs_read_super,
        .mount = yaffs_read_super,
        .kill_sb = kill_block_super,
        .fs_flags = FS_REQUIRES_DEV,
};
#endif
// MichaelTang modify end

第二处,针对Yaffs2的修改:
#ifdef CONFIG_YAFFS_YAFFS2

static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
                int silent)
{
        return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
}


// MichaelTang modify start
#if 0
static int yaffs2_read_super(struct file_system_type *fs,
                int flags, const char *dev_name, void *data,
                struct vfsmount *mnt)
{
        return get_sb_bdev(fs, flags, dev_name, data,
                        yaffs2_internal_read_super_mtd, mnt);
}
static struct file_system_type yaffs2_fs_type = {
        .owner = THIS_MODULE,
        .name = "yaffs2",
        .get_sb = yaffs2_read_super,
        .kill_sb = kill_block_super,
        .fs_flags = FS_REQUIRES_DEV,
};
#else
static struct super_block *yaffs2_read_super(struct file_system_type *fs,
                int flags, const char *dev_name,
                void *data)
{
        return mount_bdev(fs, flags, dev_name, data,
                        yaffs2_internal_read_super_mtd);
}
static struct file_system_type yaffs2_fs_type = {
        .owner = THIS_MODULE,
        .name = "yaffs2",
        //.get_sb = yaffs2_read_super,
        .mount = yaffs2_read_super,
        .kill_sb = kill_block_super,
        .fs_flags = FS_REQUIRES_DEV,
};
#endif
// MichaelTang modify end

问题5:

 error: 'MTD_OOB_AUTO' undeclared

找不到符号MTD_OOB_AUTO,新内核里名字发生了改变:

@include/mtd/mtd-abi.h

    MTD_OOB_AUTO -> MTD_OPS_AUTO_OOB

所以源码中所有的位置都改一下即可,共有2个文件使用到:

@fs/yaffs2/yaffs_mtdif1.c

@fs/yaffs2/yaffs_mtdif2.c


可能出的问题:

end_writeback找不到符号

解决方法:end_writeback(inode)改成clear_inode(inode)

---------------------------------------

另:随着Android4.0.4版本的更新,其文件系统体积也直线提升,生成的映像有250M左右,由于S5PC100内存只有256M,所以使用UBOOT烧写时就可能出问题,通过USB或tftp下载的文件系统将Uboot代码覆盖了,我们将uboot的运行地址放到最高的几M处。

假如,默认运行地址为0x27e00000,新运行地址为0x2f000000,S5PC100物理内存空间(0x20000000~0x30000000共256M)。

grep "0x27e00000" -R ./

替换了所有的地址就行了

主要是config.h、smdkc100.h和汇编代码文件中定义的几个和地址搬运有关的宏。



你可能感兴趣的:(Linux3.4.0 Yaffs2文件系统移植-支持Android4.0)