Mini2440之linux根文件系統yaffs2移植


什么是根文件系統?理論上說一個嵌入式設備如果內核能運行起來,且不需要用戶進程的話(估計這種情況很少),是不需要文件系統的。文件系統簡單的說就是一種目錄結構,由於linux操作系統的設備在系統中是以文件的形式存在,將這些文件分類管理以及提供和內核交互的接口,就形成了一定的目錄結構也就是文件系統。文件系統是為用戶反映系統的一種形式,為用戶提供一個檢測控制系統的接口。

而根文件系統,就是一種特殊的文件系統。那么根文件系統和普通的文件系統有什么區別呢?借用書上的話說就是,根文件系統就是內核啟動時掛載的第一個文件系統。由於根文件系統是啟動時掛載的第一個文件系統,那么根文件系統就要包括Linux啟動時所必須的目錄和關鍵性的文件,例如Linux 啟動時都需要有用戶進程 init 對應的文件,在Linux掛載分區時一定要會找 /etc/fstab這個掛載文件等,根文件系統中還包括了許多的應用程序,如 /bin目錄下的命令等。任何Linux啟動時所必須的文件的文件系統都可以稱為根文件系統。

一個典型的嵌入式Linux根文件系統目錄如下所示:

目錄 內容
bin 系統命令和工具
dev 系統設備文件
etc 系統初始化腳本和配置文件
lib 系統運行庫文件
proc proc文件系統
sbin 系統管理員命令和工具
sys sysfs文件系統
tmp 臨時文件
usr 用戶命令和工具,下分usr/bin和usr/sbin目錄
var 系統運行產生的可變數據

要構建一個可用的Linux根文件系統,需要的二進制和庫都不少,完全從零開始也是不現實的,推薦參考其它現有可用的文件系統,在原基礎上按需修改;或者使用文件系統制作工具如 BusyBox 來實現文件系統的生成。

一、編譯、安裝、配置 busybox

busybox編譯和環境和有很大的關系,我的操作系統版本為:

root@zhengyang:/work/sambashare/drivers/1.hello_dev# lsb_release -a
LSB Version:    core-9.20160110ubuntu0.2-amd64:core-9.20160110ubuntu0.2-noarch:security-9.20160110ubuntu0.2-amd64:security-9.20160110ubuntu0.2-noarch
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.7 LTS
Release:        16.04
Codename:       xenial

我嘗試了不同版本buybox和arm-linux-gcc后,發現有些版本編譯成功后,做成的根文件系統,在linux-5.2.8掛載時會失敗。最終發現:

  • busybox-1.25.0 + arm-linux-gcc 4.8.3

編譯運行成功了,下面我們就介紹這個環境的搭建。

1.1 下載源碼

根文件系統是根據busybox來制作的。下載地址:https://busybox.net/downloads/

這里我們就以1.25.0版本為例進行編譯安裝介紹:

注意:一般你使用什么版本的交叉編譯器來編譯linux內核時,文件系統中的所有程序也要使用同樣的交叉編譯器來編譯。

下載完成后解壓:

tar -jxvf busybox-1.25.0.tar.bz2

1.2 配置busybox

在路徑busybox-1.25.0下運行如下命令,使用默認配置:

cd ./busybox-1.25.0
make defconfig # 使用默認配置

然后進入圖像化配置頁面,修改配置 :

make menuconfig

進入Busybox Settings,配置如下參數:

Build Options --->
    Cross compile prefix:/usr/local/arm/4.8.3/bin/arm-linux-
    additional CFLAGS: -march=armv4t; s3c2440支持的指令集
    []Build BusyBox as a static binary(no shared libs)  靜態編譯,取消動態庫
    [*] Build Shared libbusybox 使用動態庫

編譯方式有兩種:

  • 第一種是以靜態方式編譯,即生成的busybox不需要動態庫的支持就能運行。這樣做我們就不需要部署動態庫了,缺點就是自己寫的程序在這個根文件系統中是不能運行的,因為缺少動態庫庫的支持。
  • 第二種方式使用動態編譯,這樣的話我們就需要部署動態庫了,在linux動態庫文件是以so為后綴,而windows下文件是以dll為后綴。

這里我們指定了arm-linux-gcc 4.8.3編譯器的路徑,這里就不具體介紹編譯器如何安裝了。

繼續配置:

Linux System Utilities --->
    [] nsenter
Coreutils --->
    []sync
Miscellaneous/Networking/...  Utilities --->
    可以擴展一些命令,比如flash_eraseall、hexdump;
Linux System Utilities --->
   [*] hexdump    

1.3 修改源碼

因為編譯時會出現錯誤,所以需要進行源碼修改,這里參考文章64位ubuntu 12.04系統編譯busybox遇到的問題處理辦法進行修改。

復制/usr/include/linux/fs.h拷貝到busybox的include文件中:

cp /usr/include/linux/fs.h ./include

修改include/fs.h,屏蔽以下3個頭文件(否則編譯時會提示找不到頭文件):

//#include <linux/limits.h>
//#include <linux/ioctl.h>
//#include <linux/types.h>

屏蔽以下幾個結構體(否則編譯時會提示找不到類型定義):

#if 0
struct fstrim_range {
        __u64 start;
        __u64 len;
        __u64 minlen;
};

/* And dynamically-tunable limits and defaults: */
struct files_stat_struct {
        unsigned long nr_files;         /* read only */
        unsigned long nr_free_files;    /* read only */
        unsigned long max_files;                /* tunable */
};

struct inodes_stat_t {
        long nr_inodes;
        long nr_unused;
        long dummy[5];          /* padding for sysctl ABI compatibility */
};
#endif

修改util-linux/blkdiscard.c中對fs.h頭文件的包含方式:

#include <linux/fs.h>修改為#include "fs.h"。

1.4 編譯

運行命令:

make

然后查看當前路徑下是否存在busybox:

root@zhengyang:/work/sambashare/busybox-1.25.0# ll busybox
-rwxr-xr-x 1 root root 1093048 1月  22 22:12 busybox*

執行make install:

make install

make install的目的就是將編譯生成的可執行程序及其依賴的庫文件、配置文件、頭文件安裝到當前系統中指定(一般都可以自己指定安裝到哪個目錄下,如果不指定一般都有個默認目錄)的目錄下,生成_install 文件夾:

root@zhengyang:/work/sambashare/busybox-1.25.0# ll _install/
總用量 24
drwxr-xr-x  6 root root 4096 2月   9 21:45 ./
drwxr-xr-x 38 root root 4096 2月   9 21:45 ../
drwxr-xr-x  2 root root 4096 2月   9 21:45 bin/
drwxr-xr-x  2 root root 4096 2月   9 21:45 lib/
lrwxrwxrwx  1 root root   11 2月   9 21:36 linuxrc -> bin/busybox*
drwxr-xr-x  2 root root 4096 2月   9 21:36 sbin/
drwxr-xr-x  4 root root 4096 2月   9 21:36 usr/

里面有5個文件: bin lib linuxrc sbin usr ,linuxrc -> bin/busybox這個linuxrc其實就是個符號鏈接。bin、sbin、usr這三個目錄里都是二進制命令工具,lib里面是庫文件,這還不足以構成 一個可用的根文件系統,必須進行其它完善工作,才能構建一個可用的根文件系統。

二、構建根文件系統

新建一個目錄用來存放制作的根文件系統,可以命名為rootfs。將利用BusyBox生成的二進制文件及目錄,即_install目錄下的所有文件及目錄復制到rootfs目錄下。

mkdir ../rootfs
cp
-a _install/* ../rootfs/

2.1 添加庫文件

切換到rootfs路徑下:

cd ../rootfs

找到交叉編譯工具里的動態庫復制到lib目錄下:

cp -a /usr/local/arm/4.8.3/arm-none-linux-gnueabi/libc/armv4t/lib/*so* ./lib

-a保留權限,復制軟鏈接本身,遞歸復制。

查看庫文件:

root@zhengyang:/work/sambashare/rootfs# ls lib
ld-2.17.so               libgomp.so.1.0.0       libnss_db.so.2          libpthread.so.0
ld-2.18.so               libid3tag.so           libnss_dns-2.17.so      libresolv-2.17.so
ld-2.9.so                libid3tag.so.0         libnss_dns-2.18.so      libresolv-2.18.so
ld-linux.so.3            libid3tag.so.0.3.0     libnss_dns-2.9.so       libresolv-2.9.so
libanl-2.17.so           libjpeg.so             libnss_dns.so.2         libresolv.so.2
libanl-2.18.so           libjpeg.so.62          libnss_files-2.17.so    librt-2.17.so
libanl-2.9.so            libjpeg.so.62.0.0      libnss_files-2.18.so    librt-2.18.so
libanl.so.1              libm-2.17.so           libnss_files-2.9.so     librt-2.9.so
libBrokenLocale-2.17.so  libm-2.18.so           libnss_files.so.2       librt.so.1
libBrokenLocale-2.18.so  libm-2.9.so            libnss_hesiod-2.17.so   libSegFault.so
libBrokenLocale-2.9.so   libmad.so              libnss_hesiod-2.18.so   libssp.so
libBrokenLocale.so.1     libmad.so.0            libnss_hesiod-2.9.so    libssp.so.0
libbusybox.so.1.25.0     libmad.so.0.2.1        libnss_hesiod.so.2      libssp.so.0.0.0
libc-2.17.so             libmemusage.so         libnss_nis-2.17.so      libstdc++.so
libc-2.18.so             libm.so.6              libnss_nis-2.18.so      libstdc++.so.6
libc-2.9.so              libmudflap.so          libnss_nis-2.9.so       libstdc++.so.6.0.13
libcidn-2.18.so          libmudflap.so.0        libnss_nisplus-2.17.so  libstdc++.so.6.0.16
libcidn.so.1             libmudflap.so.0.0.0    libnss_nisplus-2.18.so  libstdc++.so.6.0.16-gdb.py
libcrypt-2.17.so         libmudflapth.so        libnss_nisplus-2.9.so   libthread_db-1.0.so
libcrypt-2.18.so         libmudflapth.so.0      libnss_nisplus.so.2     libthread_db.so.1
libcrypt-2.9.so          libmudflapth.so.0.0.0  libnss_nis.so.2         libts-0.0.so.0
libcrypt.so.1            libnsl-2.17.so         libpcprofile.so         libts-0.0.so.0.1.1
libc.so.6                libnsl-2.18.so         libpng12.so             libts.so
libdl-2.17.so            libnsl-2.9.so          libpng12.so.0           libutil-2.17.so
libdl-2.18.so            libnsl.so.1            libpng12.so.0.35.0      libutil-2.18.so
libdl-2.9.so             libnss_compat-2.17.so  libpng.so               libutil-2.9.so
libdl.so.2               libnss_compat-2.18.so  libpng.so.3             libutil.so.1
libgcc_s.so              libnss_compat-2.9.so   libpng.so.3.35.0        libuuid.so
libgcc_s.so.1            libnss_compat.so.2     libpthread-2.17.so      libuuid.so.1
libgomp.so               libnss_db-2.17.so      libpthread-2.18.so      libuuid.so.1.2
libgomp.so.1             libnss_db-2.18.so      libpthread-2.9.so

隨便查看一個文件的屬性信息,可以看到都是基於armv4t指令集:

root@zhengyang:/work/sambashare/rootfs# arm-linux-readelf -A ./lib/libc.so.6
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "4T"
  Tag_CPU_arch: v4T
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_rounding: Needed
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int

這里只是拷貝動態鏈接庫。一般開發程序使用動態編譯需要板子上動態庫的支持才能運行,所以拷貝動態庫。

一般使用gcc編譯后的可執行文件、目標文件和動態庫都帶有調試信息和符號信息,這些在調試的時候用到,但是卻增大了文件的大小。通常在PC上調試,或者調試時使用這些帶有調試信息和符號信息的庫文件,程序發布后使用去掉這些信息的庫文件,可以大大縮小根文件系統的體積。這里我們去掉這些信息,方法是使用strip工具:

 cd ./lib
arm-linux-strip ./*

2.2 構建etc目錄

初始化配置腳本放在在/etc目錄下,用於系統啟動所需的初始化配置腳本。BusyBox提供了一些初始化范例腳本,在examples/bootfloppy/etc/目錄下:

root@zhengyang:/work/sambashare/busybox-1.25.0# ll examples/bootfloppy/etc/
總用量 24
drwxr-xr-x 3 root root 4096 12月  5  2018 ./
drwxr-xr-x 3 root root 4096 12月  5  2018 ../
-rw-r--r-- 1 root root   33 12月  5  2018 fstab
drwxr-xr-x 2 root root 4096 12月  5  2018 init.d/
-rw-r--r-- 1 root root  100 12月  5  2018 inittab
-rw-r--r-- 1 root root  133 12月  5  2018 profile

在rootfs目錄,創建etc文件夾:

mkdir etc

將這些配置文件復制到新制作的根文件系統etc目錄下。

root@zhengyang:/work/sambashare/rootfs# cp -a ../busybox-1.25.0/examples/bootfloppy/etc/* ./etc
/root@zhengyang:/work/sambashare/rootfs# ll etc 總用量 24 drwxr-xr-x 3 root root 4096 1月 23 22:05 ./ drwxr-xr-x 13 root root 4096 1月 23 21:54 ../ -rw-r--r-- 1 root root 33 12月 5 2018 fstab drwxr-xr-x 2 root root 4096 12月 5 2018 init.d/ -rw-r--r-- 1 root root 100 12月 5 2018 inittab -rw-r--r-- 1 root root 133 12月 5 2018 profile
2.2.1. 修改/etc/inittab文件

/etc/inittab文件是init進程解析的配置文件,通過這個配置文件決定執行哪個進程,何時執行。將文件修改為:

# 系統啟動時
::sysinit:/etc/init.d/rcS

# 系統啟動按下Enter鍵時
::askfirst:-/bin/sh

# 按下Ctrl+Alt+Del鍵時
::ctrlaltdel:/sbin/reboot

# 系統關機時
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

# 系統重啟時
::restart:/sbin/init

以上內容定義了系統啟動時,關機時,重啟時,按下Ctrl+Alt+Del鍵時執行的進程。

2.2.2. 修改/etc/init.d/rcS文件
#!/bin/sh

# 掛載 /etc/fstab 中定義的所有文件系統
/bin/mount -a

# 掛載虛擬的devpts文件系統用於用於偽終端設備
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts

# 使用mdev動態管理u盤和鼠標等熱插拔設備
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug

# 掃描並創建節點
/sbin/mdev -s

修改init.d文件權限:

 chmod -R 777 init.d/*
2.2.3. 修改/etc/fstab 

/etc/fstab文件存放的是文件系統信息。在系統啟動后執行/etc/init.d/rcS文件里/bin/mount -a命令時,自動掛載這些文件系統。

# <file system>    <mount point>    <type>    <options>    <dump>    <pass>     
proc                  /proc          proc     defaults       0         0
sysfs                 /sys           sysfs    defaults       0         0
tmpfs                 /tmp           tmpfs    defaults       0         0
tmpfs                 /dev           tmpfs    defaults       0         0

這里我們掛載的文件系統有三個proc、sysfs和tmpfs,在內核中proc和sysfs默認都支持,而tmpfs是沒有支持的,我們需要添加tmpfs的支持。

2.2.4. 修改/etc/profile文件

/etc/profile文件作用是設置環境變量,每個用戶登錄時都會運行它,將文件內容修改為:

# 主機名
export HOSTNAME=zy

# 用戶名
export USER=root

# 用戶目錄
export HOME=/root

# 終端默認提示符
export PS1="[$USER@$HOSTNAME:\$PWD]\# "    

# 環境變量
export PATH=/bin:/sbin:/usr/bin:/usr/sbin

# 動態庫路徑
export LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH

2.3 構建dev目錄

在rootfs目錄,創建dev文件夾:

mkdir dev

創建終端文件:

sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3

2.4 構建其他文件

mkdir mnt proc tmp sys root

三、根文件系統類型

如果文件系統已經布局完成, 則可以發到目標中了。通常會制作一個鏡像然后通過某種方式固化到目標系統中,具體采用哪種根文件系統類型發布需要根據資源狀況、內核情況和系統需求等方面進行裁決:

  • 硬件方面:至少需要考慮主存儲介質的類型和大小如FLASH是NOR FLASH還是NAND FLASH,RAM的大小等;
  • 內核方面: 則需考慮所裁剪后的內核支持哪些文件系統,采用哪根文件系統最合適, 能滿足性、速度等要求;
  • 系統需求方面:要考慮運行速度、是否可寫壓縮等因素;

常見的可用於根文件系統類型有ramdisk 、cramfs、jffs2 、yaffs/yaffs2和 ubifs等,各類型的特性如表所列:

類型 介質 是否壓縮 是否可寫 掉電保存 存在於RAM中
ramdisk  
cramfs   -
jffs2 NOR FLASH
yaffs/yaffs2 NAND FLASH
ubifs NAND FLASH

盡管文件系統固件以某一種文件系統的鏡像發布,但是整個文件系統實際上還是並存多種邏輯文件系統的。例如,一個系統根文件系統以ubifs掛載,但是/dev目錄卻是以tmpfs掛載的、/sys目錄掛載的是sysfs文件系統。

四、制作.yaffs2根文件系統

YAFFS目前有yaffs、yaffs2兩個版本,一般來說:

  • yaffs對小頁(512B+16B/頁)的NAND FLASH(64M)有很好的支持;
  • yaffs2對大頁(2K+64B/頁)的NAND FLASH(128M、256M或者更大)支持更好;

Mini2440開發板采用了的256MB的Nand Flash(型號K9F2G08U0C)

4.1 下載yaffs2源碼

下載:

git clone git://www.aleph1.co.uk/yaffs2
root@zhengyang:/work/sambashare# git clone git://www.aleph1.co.uk/yaffs2
正克隆到 'yaffs2'...
remote: Enumerating objects: 9284, done.
remote: Counting objects: 100% (9284/9284), done.
remote: Compressing objects: 100% (5813/5813), done.
remote: Total 9284 (delta 7389), reused 4363 (delta 3374)
接收對象中: 100% (9284/9284), 3.85 MiB | 6.00 KiB/s, 完成.
處理 delta 中: 100% (7389/7389), 完成.
檢查連接... 完成。
root@zhengyang:/work/sambashare# ll
總用量 165132
drwxr-xr-x 26 root root      4096 1月  23 22:49 ./
drwxr-xr-x  7 root root      4096 1月  22 23:37 ../
drwxrwxrwx  5 root root      4096 1月  23 00:05 10.bootloader/
drwxrwxrwx  6 root root      4096 1月  23 00:05 11.dm9000/
drwxrwxrwx  2 root root      4096 1月  23 00:05 1.led_asm/
drwxrwxrwx  2 root root      4096 1月  23 00:05 2.led_c/
drwxrwxrwx  2 root root      4096 1月  23 00:05 3.clock/
drwxrwxrwx  6 root root      4096 1月  23 00:05 4.uart/
drwxrwxrwx  5 root root      4096 1月  23 00:05 5.int/
drwxrwxrwx  5 root root      4096 1月  23 00:05 6.nand_flash/
drwxrwxrwx  7 root root      4096 1月  23 00:05 7.lcd/
drwxrwxrwx  5 root root      4096 1月  23 00:05 8.adc/
drwxrwxrwx  5 root root      4096 1月  23 00:05 9.sdram/
drwxr-xr-x 37 root root      4096 1月  23 00:25 busybox-1.25.0/
drwxrwxrwx  2 root root      4096 1月  22 23:56 images/
drwxrwxr-x 24 root root      4096 1月  23 20:58 linux-5.2.8/
-rw-r--r--  1 root root 164485696 8月  10  2019 linux-5.2.8.tar.gz
drwxrwxrwx  2 root root      4096 1月  22 23:56 mini2440.jflash/
drwxr-xr-x 13 root root      4096 1月  23 21:54 rootfs/
-rw-r--r--  1 root root   4493588 1月  23 22:27 rootfs-jffs2.bin
drwxrwxrwx  3 root root      4096 1月  22 23:56 SJF2440燒寫工具/
drwxr-xr-x  2 root root      4096 1月  23 00:23 tools/
drwxrwxrwx 23 root root      4096 1月  23 00:12 u-boot-2016.05-crop/
drwxrwxrwx 23 root root      4096 1月  23 00:21 u-boot-2016.05-linux/
drwxrwxrwx 23 root root      4096 1月  23 00:14 u-boot-2016.05-nand-flash/
drwxrwxrwx 23 root root      4096 1月  23 00:05 u-boot-2016.05-nor-flash/
drwxr-xr-x  9 root root      4096 1月  23 22:56 yaffs2/
drwxrwxrwx  5 root root      4096 1月  23 00:05 zk/
-rwxrw-rw-  1 root root        91 10月 17 23:19 問題解決.txt*

4.2 配置內核支持yaffs2

將yaffs文件夾復制到linux-5.2.8/fs路徑下,使內核支持yaffs2文件系統。,:

cd yaffs2
./patch-ker.sh c m /work/sambashare/linux-5.2.8   // 將yaffs2文件夾copy到linux-5.2.8/fs下

我的linux內核路徑在/work/sambashare/linux-5.2.8,修改成你們自己的。

進入linux內核源碼目錄:

cd ../linux-5.2.8
make s3c2440_defconfig 
make menuconfig

在上一節配置的基礎上,繼續配置linux內核使其支持yaffs2根文件系統:

File systems  --->

 [*] Miscellaneous filesystems  --->

 <*>   yaffs2 file system support

因為arm-none-linux-gnueabi 4.8.3使用了EABI方式,所以這就需要內核同樣配置EABI編譯屬性才能支持EABI編譯出來的應用程序busybox。

Kernel Features --->

[*] Use the ARM EABI to compile the kernel

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

選中后按下Y,並保存為s3c2440_defconfig:

存檔:

mv s3c2440_defconfig ./arch/arm/configs/

重新編譯linux內核,記得切換交叉編譯環境為arm-linux-gcc 4.8.3版本:

make s3c2440_defconfig    // 必須執行,不然配置的不會生效
make uImage

編譯內核,將會出現一些錯誤:

出現錯誤的原因,主要是由於yaffs2的更新速度跟不上內核的更新速度,所以只能自己做一些修改。

 在fs/yaffs2/yaffs_vfs.c文件中,yaffs2對不同版本的linux做了適配,但是當前我下載yaffs2僅僅支持到4.16版本的內核,再高版本就需要自己做適配。這里我們參考移植linux-5.4.26到jz2440進行修改。

4.3 內核編譯錯誤解決

4.3.1. current_kernel_time64被移除
fs/yaffs2/yaffs_vfs.c:1411:3: error: implicit declaration of function 'current_kernel_time64' [-Werror=implicit-function-declaration]

從上述信息來看,很可能是current_kernel_time64這個接口被移除了,那我們就需要找到其替代者。最快速的解決方法就是去網上搜索,大概率這類錯誤已經被前人解決。這里給結論:使用ktime_get_coarse_real_ts64替代。其實最權威的資料是內核文檔,遇到這類問題直接搜文檔,比如這里的時間接口,見linux-5.2.28\Documentation\core-api\timekeeping.rst:

 修改yaffs_vfs.c文件:

#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
#define update_dir_time(dir) do {\
        (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
    } while (0)
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
#define update_dir_time(dir) do {\
        (dir)->i_ctime = (dir)->i_mtime = current_kernel_time(); \
    } while (0)
#else
#define update_dir_time(dir) do {\ ktime_get_coarse_ts64(&(dir)->i_mtime); \ (dir)->i_ctime = (dir)->i_mtime; \
    } while (0)
#endif
4.3.2. MS_RDONLY未聲明

再次編譯內核,錯誤信息為:

fs/yaffs2/yaffs_vfs.c:2741:25: error: 'MS_RDONLY' undeclared (first use in this function)
fs/yaffs2/yaffs_vfs.c:2741:25: note: each undeclared identifier is reported only once for each function it appears in
fs/yaffs2/yaffs_vfs.c: In function 'yaffs_internal_read_super':
fs/yaffs2/yaffs_vfs.c:2918:17: error: 'MS_NOATIME' undeclared (first use in this function)
fs/yaffs2/yaffs_vfs.c:2920:30: error: 'MS_RDONLY' undeclared (first use in this function)
scripts/Makefile.build:278: recipe for target 'fs/yaffs2/yaffs_vfs.o' failed
make[2]: *** [fs/yaffs2/yaffs_vfs.o] Error 1
scripts/Makefile.build:489: recipe for target 'fs/yaffs2' failed
make[1]: *** [fs/yaffs2] Error 2
Makefile:1074: recipe for target 'fs' failed
make: *** [fs] Error 2

解決方案很簡單, 修改yaffs_vfs.c文件:添加頭文件:

#include <uapi/linux/mount.h>
4.3.3. current_kernel_time被移除

再次編譯內核,錯誤信息為:

fs/yaffs2/yaffs_attribs.c: In function 'yaffs_load_current_time':
fs/yaffs2/yaffs_attribs.c:55:2: error: implicit declaration of function 'current_kernel_time' [-Werror=implicit-function-declaration]
fs/yaffs2/yaffs_attribs.c:55:19: error: request for member 'tv_sec' in something not a structure or union
cc1: some warnings being treated as errors
scripts/Makefile.build:278: recipe for target 'fs/yaffs2/yaffs_attribs.o' failed
make[2]: *** [fs/yaffs2/yaffs_attribs.o] Error 1
scripts/Makefile.build:489: recipe for target 'fs/yaffs2' failed
make[1]: *** [fs/yaffs2] Error 2
Makefile:1074: recipe for target 'fs' failed
make: *** [fs] Error 2

定位到fs/yaffs2/yaffs_attribs.c報錯的函數:

void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
{
    obj->yst_mtime = Y_CURRENT_TIME;
    if (do_a)
        obj->yst_atime = obj->yst_mtime;
    if (do_c)
        obj->yst_ctime = obj->yst_mtime;
}

搜索關鍵字Y_CURRENT_TIME:

root@zhengyang:/work/sambashare/linux-5.2.8# grep "Y_CURRENT_TIME" fs/yaffs2/* -nR
fs/yaffs2/yaffs_attribs.c:55:   obj->yst_mtime = Y_CURRENT_TIME;
fs/yaffs2/yportenv.h:67:#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
fs/yaffs2/yportenv.h:69:#define Y_CURRENT_TIME current_kernel_time().tv_sec
fs/yaffs2/yportenv.h:74:#define Y_CURRENT_TIME CURRENT_TIME
fs/yaffs2/yportenv.h:76:#define Y_CURRENT_TIME current_kernel_time()

用新的接口重新定義這個宏即可,修改fs/yaffs2/yportenv.h文件:

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
#else
//#define Y_CURRENT_TIME current_kernel_time().tv_sec
#define Y_CURRENT_TIME ({ struct timespec64 ts64; ktime_get_coarse_ts64(&ts64); ts64.tv_sec; })
#endif
#define Y_TIME_CONVERT(x) (x).tv_sec
#else
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
#define Y_CURRENT_TIME CURRENT_TIME
#else
#define Y_CURRENT_TIME current_kernel_time()
#endif
#define Y_TIME_CONVERT(x) (x)
#endif

進行上述修改后,重新執行make uImage,編譯通過。

4.4  制作工具mkyaffs2image

yaffs2文件系統是針對NAND FLASH的文件系統,其制作工具為mkyaffs2image。不同容量的NAND FLASH,工具也是不一樣的。

mkyaffs2image是在yaffs2文件系統的utils目錄下,只把其中的chunkSize 、spareSize與 pagesPerBlock幾個變量,按照你使用的NAND FLASH芯片參數的改一下就可以用。

cd yaffs2/utils/
vim mkyaffs2image.c

修改為:

// Adjust these to match your NAND LAYOUT:
#define chunkSize 2048
#define spareSize 64
#define pagesPerBlock 64

然后在當前路徑下進行編譯:

make

出現若干錯誤,錯誤信息如下:

root@zhengyang:/work/sambashare/yaffs2/utils# make
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline mkyaffsimage.c -o mkyaffsimage.o
In file included from mkyaffsimage.c:30:0:
yaffs_guts.h:497:2: error: unknown type name ‘YTIME_T’
  YTIME_T yst_uid;
  ^
yaffs_guts.h:498:2: error: unknown type name ‘YTIME_T’
  YTIME_T yst_gid;
  ^
yaffs_guts.h:499:2: error: unknown type name ‘YTIME_T’
  YTIME_T yst_atime;
  ^
yaffs_guts.h:500:2: error: unknown type name ‘YTIME_T’
  YTIME_T yst_mtime;
  ^
yaffs_guts.h:501:2: error: unknown type name ‘YTIME_T’
  YTIME_T yst_ctime;
  ^
yaffs_guts.h:1076:1: error: unknown type name ‘YTIME_T’
 YTIME_T yaffs_oh_ctime_fetch(struct yaffs_obj_hdr *oh);
 ^
yaffs_guts.h:1077:1: error: unknown type name ‘YTIME_T’
 YTIME_T yaffs_oh_mtime_fetch(struct yaffs_obj_hdr *oh);
 ^
yaffs_guts.h:1078:1: error: unknown type name ‘YTIME_T’
 YTIME_T yaffs_oh_atime_fetch(struct yaffs_obj_hdr *oh);
 ^
Makefile:56: recipe for target 'mkyaffsimage.o' failed
make: *** [mkyaffsimage.o] Error 1

定義到../yaffs_guts.h文件錯誤信息所在行:

#ifdef CONFIG_YAFFS_WINCE
    //these are always 64 bits
    u32 win_ctime[2];
    u32 win_mtime[2];
    u32 win_atime[2];
#else
    //these can be 32 or 64 bits
    YTIME_T yst_uid;
    YTIME_T yst_gid;
    YTIME_T yst_atime;
    YTIME_T yst_mtime;
    YTIME_T yst_ctime;
#endif

這個好解決,在../yaffs_guts.h中加上如下定義::

#ifndef YTIME_T
#define YTIME_T  time_t             
#endif

再次編譯,出現新的錯誤:

In file included from mkyaffs2image.c:35:0:
yaffs_endian.h:28:15: error: unknown type name ‘u64’
 static inline u64 swap_u64(u64 val)
               ^
yaffs_endian.h:28:28: error: unknown type name ‘u64’
 static inline u64 swap_u64(u64 val)
                            ^
yaffs_endian.h: In function ‘swap_ytime_t’:
yaffs_endian.h:43:32: error: ‘u64’ undeclared (first use in this function)
  if (sizeof(YTIME_T) == sizeof(u64))
                                ^
yaffs_endian.h:43:32: note: each undeclared identifier is reported only once for each function it appears in
yaffs_endian.h:44:10: error: implicit declaration of function ‘swap_u64’ [-Werror=implicit-function-declaration]
   return swap_u64(val);
          ^
yaffs_endian.h:44:3: error: nested extern declaration of ‘swap_u64’ [-Werror=nested-externs]
   return swap_u64(val);
   ^
cc1: all warnings being treated as errors
Makefile:56: recipe for target 'mkyaffs2image.o' failed
make: *** [mkyaffs2image.o] Error 1

在../yaffs_endian.h文件添加如下定義:

typedef unsigned long long u64;

再次編譯,編譯成功:

root@zhengyang:/work/sambashare/yaffs2/utils# make
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline mkyaffsimage.c -o mkyaffsimage.o
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline yaffs_hweight.c -o yaffs_hweight.o
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline yaffs_ecc.c -o yaffs_ecc.o
gcc -o mkyaffsimage  mkyaffsimage.o yaffs_hweight.o yaffs_ecc.o
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline mkyaffs2image.c -o mkyaffs2image.o
gcc -c -O2 -Wall -Werror -DCONFIG_YAFFS_UTIL -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline yaffs_packedtags2.c -o yaffs_packedtags2.o
gcc -o mkyaffs2image mkyaffs2image.o yaffs_packedtags2.o yaffs_hweight.o yaffs_ecc.o
root@zhengyang:/work/sambashare/yaffs2/utils# ll
總用量 124
drwxr-xr-x 2 root root  4096 1月  25 00:34 ./
drwxr-xr-x 9 root root  4096 1月  24 22:04 ../
-rw-r--r-- 1 root root  2164 1月  23 22:56 Makefile
-rwxr-xr-x 1 root root 19400 1月  25 00:34 mkyaffs2image*
-rw-r--r-- 1 root root 14193 1月  23 22:56 mkyaffs2image.c
-rw-r--r-- 1 root root 11440 1月  25 00:34 mkyaffs2image.o
-rwxr-xr-x 1 root root 18696 1月  25 00:34 mkyaffsimage*
-rw-r--r-- 1 root root 13787 1月  23 22:56 mkyaffsimage.c
-rw-r--r-- 1 root root 10408 1月  25 00:34 mkyaffsimage.o
lrwxrwxrwx 1 root root    14 1月  24 21:56 yaffs_ecc.c -> ../yaffs_ecc.c
lrwxrwxrwx 1 root root    14 1月  24 21:56 yaffs_ecc.h -> ../yaffs_ecc.h
-rw-r--r-- 1 root root  3376 1月  25 00:34 yaffs_ecc.o
lrwxrwxrwx 1 root root    17 1月  24 21:56 yaffs_endian.h -> ../yaffs_endian.h*
lrwxrwxrwx 1 root root    15 1月  24 21:56 yaffs_guts.h -> ../yaffs_guts.h*
lrwxrwxrwx 1 root root    25 1月  24 21:56 yaffs_hweight.c -> ../direct/yaffs_hweight.c
lrwxrwxrwx 1 root root    25 1月  24 21:56 yaffs_hweight.h -> ../direct/yaffs_hweight.h
-rw-r--r-- 1 root root  2096 1月  25 00:34 yaffs_hweight.o
lrwxrwxrwx 1 root root    22 1月  24 21:56 yaffs_list.h -> ../direct/yaffs_list.h
lrwxrwxrwx 1 root root    22 1月  24 21:56 yaffs_packedtags2.c -> ../yaffs_packedtags2.c
lrwxrwxrwx 1 root root    22 1月  24 21:56 yaffs_packedtags2.h -> ../yaffs_packedtags2.h
-rw-r--r-- 1 root root  3112 1月  25 00:34 yaffs_packedtags2.o
lrwxrwxrwx 1 root root    16 1月  24 21:56 yaffs_trace.h -> ../yaffs_trace.h
lrwxrwxrwx 1 root root    20 1月  24 21:56 yportenv.h -> ../direct/yportenv.h
-rw-r--r-- 1 root root   962 1月  23 22:56 yutilsenv.h

4.5 生成yaffs2類型的根文件系統

切換到頂層路徑運行命令制作根文件系統:

cd /work/sambashare
./yaffs2/utils/mkyaffs2image ./rootfs/ rootfs.yaffs2

查看制作好的根文件系統:

五、編譯下載

5.1 下載到開發版

5.2 設置u-boot啟動參數

u-boot啟動后,在倒計時結束前按下空格鍵,設置machid:

SMDK2440 # set machid 0xA8
SMDK2440 # save
Saving Environment to NAND...
Erasing NAND...

Erasing at 0x40000 -- 100% complete.
Writing to NAND... OK
SMDK2440 # 

設置啟動參數:

set bootargs "root=/dev/mtdblock3 console=ttySAC0,115200 rootfstype=yaffs2 init=/linuxrc"
save

5.3 重新啟動u-boot、引導linux內核

重新啟動開發板,NAND啟動,運行,在串口輸出的最后有如下錯誤:

使用自己制作的mkyaffs2image工具生成的yaffs2根文件系統總是出現這個錯誤。后來我嘗試將友善之家提供的根文件系統rootfs_rtm_2440.img下載到開發板運行,發現可以正常運行,從這里說明我們的linux內核程序是沒有問題的,但是根文件系統存在問題。

5.4 第三方根文件系統源碼及工具

為了排查根文件系統的問題,我從網上下載了mkyaffs2image 256M工具,並復制到/work/sambashare路徑下,然后重新制作yaffs2根文件系統:

cd /work/sambashare
./mkyaffs2image ./rootfs/ rootfs.yaffs2

再次下載到開發板啟動,發現運行成功了:

六、代碼下載

Young / s3c2440_project[u-boot-2016.05-linux、linux-5.2.8、yaffs2、busybox-1.25.0]

參考文章:

[1]二十.Linux開發之根文件系統構建及過程詳解

[2]制作嵌入式Linux根文件系

[3]JZ2440:yaffs2 格式根文件系統制作 - 程序員大本營

[4]S3C6410使用---13mkyaffs2image

[5]S3C2440移植linux3.4.2內核之支持YAFFS文件系統

[6]嵌入式Linux構建yaffs根文件系統

[7]yaffs2移植到內核linux-4.4.16的修改記錄


免責聲明!

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



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