折腾了一个星期,终于能做到mini2440上的东西都是自己做的或者配置的了。
只记录一下流程,具体细节都可以在网上找到资料
创建最小文件系统:
用的交叉编译器是友善的4.4.3,因为编译最新版busybox1.24.1有错
util-linux/umount.c: In function 'umount_main':
util-linux/umount.c:87: error: 'MNT_DETACH' undeclared (first use in this function)
util-linux/umount.c:87: error: (Each undeclared identifier is reported only once
util-linux/umount.c:87: error: for each function it appears in.),上网查找原因是交叉编译的glibc太老,又不能不用umount这个命令,所以用14年的busybox1.22.1重新编译可以使用,首先也是修改顶层makefile中的arch和cross_compile(make menuconfig中也可以配置cross_compile),然后make再make install就会生成在_INSTALL下的文件系统。
内核最终会跳入start_kernel()函数,并开始执行init(系统的第一个进程),如果bootloader传入参数有init=xxx则执行xxx否则执行/bin/init,/sbin/init等,用busybox的init则是init=/linuxrc,init会按照/etc/inittab文件的内容执行程序,inittab文件格式这里不说了,可以通过find -name查找busybox中的inittab文档,也可以看网上的资料。还要有/dev/console和/dev/null,用mknod命令生成,主次设备号可以看pc机下的console和null,前者是5,1后者是1,3都是字符设备c。然后可以用udev机制自动创建/dev下设备(bosybox有文档,网上资料也很多),设置fstab这个mount需要的配置文件。因为busybox选择的动态编译,因此要把PC上交叉编译的用到库拷到最小文件系统下,这样一个最小文件系统就差不多了。
配置内核支持yaffs文件系统(探索最新内核4.3)
内核在里程碑的2.6之后已经收录了mini2440的配置文件,因此只要make mini2440_defconfig就可以完成配置,因此不用修改时钟mtd分区了,唯一要做的就是设置内核支持yaffs文件系统。
linux内核并没有自带支持yaffs,所以上yaffs官网下载源码,阅读里面的README得知在yaffs源码目录下执行./patch-ker.sh c m $linux内核目录,会修改makefile和kconfig,make menuconfig会在文件系统中发现yaffs这项新选项,选中了之后使用默认配置即可(2K大页)。
最开始我使用最新的4.3内核进行配置出现:
fs/yaffs2/yaffs_vfs.c:286: error: 'struct file' has no member named 'f_dentry'
fs/yaffs2/yaffs_vfs.c:779: error: 'do_sync_read' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:780: error: 'do_sync_write' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:781: error: unknown field 'aio_read' specified in initializer
fs/yaffs2/yaffs_vfs.c:781: error: 'generic_file_aio_read' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:782: error: unknown field 'aio_write' specified in initializer
fs/yaffs2/yaffs_vfs.c:782: error: 'generic_file_aio_write' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:787: error: 'generic_file_splice_write' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:1067: error: implicit declaration of function 'nd_set_link'
第一个错误经过对比新老内核发现,在新内核的fs.h中的file结构体中少了#define f_dentry f_path.dentry
之后的错误都是内核中采用了新函数或者新结构,参照新内核的nfs和jffs源码修改(注释的是原版):
static const struct file_operations yaffs_file_operations = {
.read = seq_read或者new_sync_read(不确定是哪个),//do_sync_read,
.write = seq_write或者new_sync_write(不确定是哪个),//do_sync_write,
.read_iter = generic_file_read_iter,//.aio_read = generic_file_aio_read,
.write_iter = generic_file_write_ite,r//.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.flush = yaffs_file_flush,
.fsync = yaffs_sync_object,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,//generic_file_splice_write,
.llseek = generic_file_llseek,
};
最后一个错误nd_set_link这个函数已经没有了,在老内核中找到源码:
static inline void nd_set_link(struct nameidata *nd, char *path)
{
nd->saved_names[nd->depth] = path;
}
但是4.3内核中对nameidata机构体的定义变了,没有办法直接用。原来是:
struct nameidata {
struct path path;
struct qstr last;
struct path root;
unsigned int flags;
int last_type;
unsigned depth;
char *saved_names[MAX_NESTED_LINKS + 1];
/* Intent data */
union {
struct open_intent open;
} intent;
}
现在是:
struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq, m_seq;
int last_type;
unsigned depth;
int total_link_count;
struct saved {
struct path link;
void *cookie;
const char *name;
struct inode *inode;
unsigned seq;
} *stack, internal[EMBEDDED_LEVELS];
struct filename *name;
struct nameidata *saved;
unsigned root_seq;
int dfd;
}
对比新老版本内核的nfs和jffs文件系统中链接文件的实现,发现nd_set_link()并不是简单地被新内核中的新函数代替了,而是引入了cookie变量实现链接,我实在是黔驴技穷了。。
最后用了3.x版本内核的最新一个3.18.24,配置和之前一样,make zImage后出现:
fs/yaffs2/yaffs_vfs.c:781: error: 'generic_file_aio_read' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:782: error: 'generic_file_aio_write' undeclared here (not in a function)
fs/yaffs2/yaffs_vfs.c:787: error: 'generic_file_splice_write' undeclared here (not in a function)
有了之前经验,很好解决(注释掉的是原版)
static const struct file_operations yaffs_file_operations = {
.read = new_sync_read,//do_sync_read
.write = new_sync_write,//do_sync_write
.read_iter = generic_file_read_iter,//.aio_read = generic_file_aio_read
.write_iter = generic_file_write_iter,//.aio_write = generic_file_aio_write
.mmap = generic_file_mmap,
.flush = yaffs_file_flush,
.fsync = yaffs_sync_object,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,//generic_file_splice_write
.llseek = generic_file_llseek,
}
这里要说一下read和write,其实在3.18.24内核中是有do_sync_read和do_sync_write的,但是这样生成的内核烧到板子会显示:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
LR is at do_sync_read
所以我猜测是do_sync_read函数有问题,再fs.h中发现do_sync_read()声明的下面有一个new_sync_read(),并且其他文件系统就是用的这个函数,尝试了一下板子果然可以正常启动。但是会显示:
random: nonblocking pool is initialized 希望有大侠可以帮助解决
至此,板子上的引导是自己写的,内核是站在巨人肩膀修改的,文件系统是自己配置的。终于对嵌入式linux系统开发有了总体的认识,暂时不准备深入挖掘内核,下一步学习嵌入式linux的应用开发,但是对linux的热情和探索热情不会减~
阅读(5107) | 评论(0) | 转发(0) |