备忘一次嵌入式实训之二 根文件系统制作及led驱动
三 制作根文件系统
说明:
三种启动方式的根文件系统制作大致相同,细微区别将会说明。
制作根文件系统的busybox版本为busybox-1.15.2;
1.创建根文件系统目录:
#cd转入到你的工作目录。
#mkdir rootfs
#cd rootfs
#mkdir bin dev etc lib proc sbin sys usr mnt tmp var
#mkdir usr/bin usr/lib usr/sbin lib/modules etc/sysconfig
2. 创建最基本的设备文件:
#cd dev
#mknod -m 666 console c 5 1
#mknod -m 666 null c 1 3
#cd ..
3. 安装/etc配置文件
etc/fstab文件:
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
var /dev tmpfs defaults 0 0
etc/inittab文件:
#/etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
etc/init.d/rcS文件:
#!/bin/sh
echo "Processing /etc/init.d/rcS"
echo "mount -a"
mount -a
exec /etc/rc.local
etc/rc.local文件:
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
runlevel=S
prevlevel=N
export PATH runlevel prevlevel
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo "Processing /etc/rc.local"
echo "get hostname"
/bin/hostname -F /etc/sysconfig/HOSTNAME
echo "Starting mdev"
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
mkdir -p /var/lock
echo "ifconfig eth0 10.10.66.135 netmask 255.255.255.0 up"
ifconfig eth0 10.10.66.135 netmask 255.255.255.0 up
echo "**************************************************"
echo " “
echo " Linux 2.6.36 ”
echo " “
echo " by lc ”
echo " “
echo " 2012-12-16 ”
echo " “
echo "**************************************************"
etc/sysconfig/HOSTNAME 文件:
lvchao-study (可任意取)
etc/profile 文件:
# /etc/profile: system-wide .profile file for the Bourne shells
# Ash profile
# vim: syntax=sh
# No core files by default
#ulimit -S -c 0 > /dev/null 2>&1
USER="`id -un`"
LOGNAME=$USER
PS1='[\u@\h]# '
PATH=$PATH
HOSTNAME=`/bin/hostname`
echo "Processing /etc/profile... "
echo "Done"
export USER LOGNAME PS1 PATH
etc/passwd 文件:
#username:password:User ID:Group ID:comment:home directory:shell
root:x:0:0:root:/root:/bin/sh
在etc目录执行命令
>touchmdev.conf
PS: 上面步骤可以使用脚本自动完成,请参见附件rootfs.sh(需root权限)
4. 编译内核模块:
#cd linux-2.6.36
#make modules
5. 安装内核模块:
#make modules_install INSTALL_MOD_PATH=/xxx/rootfs
6. 配置busybox
#cd busybox-xxx
#make menuconfig,配置如下:
Busybox Settings -> build Options ->选中"Build busybox as a static
binary“,即静态链接,免去拷贝大量的库文件,但是这就导致在编译驱动测试程序的时候加上编译参数 -static 。
Installation Options -> 选中"Don't use /usr",以免busybox不慎被安装到
宿主机系统的相应目录下,破坏宿主机系统。
Busybox Installation Prefix (/xxx/rootfs),修改该选项表明编译后的
busybox将安装到该位置。
添加
Busybox Settings --->
Busybox Library Tuning --->
[*] Fancy shell prompts
//Setting this option allows for prompts to use things like \w and $ and escape codes.
PS: 如果遇到’Makefile:1270: *** 混和的隐含和普通规则。 停止‘之类的错误,无法进入配置图形界面,需修改其Makefile文件,编辑Makefile
查找这里使用的busybox1270
/ %/: prepare scripts FORCE
修改为
%/: prepare scripts FORCE
查找 422
config %config: scripts_basic outputmakefile FORCE
修改为
%config: scripts_basic outputmakefile FORCE
造成这种错误的原因是版本gcc版本过高
7. 编译、安装busybox
#make ARCH=arm CROSS_COMPILE=arm-linux-
#make install
安装到Busybox Installation Prefix (/xxx/rootfs)设定的目录里。
完成根文件系统的创建
8. 因为initramfs根文件系统启动时执行的第一个程序是init,而不是
linuxrc,所以在此,我们制作的根文件系统需要添加一个init文件,
相应的linuxrc文件就不再需要了。
按照如下方式修改根文件系统
#cd /xxx/rootfs //切换到根文件系统目录
#ln -s bin/busybox init
因为initramfs根文件系统启动时执行的第一个程序是init,而不是linuxrc,所以在此,我们制作的根文件系统需要添加一个init文件,相应的linuxrc文件就不再需要了
注意:
此文档说明的是initramfs启动Linux方法,所以跟文件系统制作到此便结束
了,如果你需要的是ramdisk方式启动linux,那么你还需要将其打包成randisk镜像,并且linuxrc文件也是必要的。
打包方法如下:
(1)dd if=/dev/zero of=ramdisk.img bs=4k count=4096,这样制作的镜像有4MB,可以根据自己的需要修改
(2)mkfs.ext2 -m0 ramdisk.img,将ramdisk.img格式化为ext2格式
(3)mount -o loop ramdisk.img /mnt/ramdisk/,将ramdisk.img挂载到/mnt/ramdisk目录
(4)cp -a /rootfs /mnt/ramdisk,将自己的文件系统全部拷贝到/mnt/ramdisk目录
(5)umount /mnt/ramdisk,卸载ramdisk挂载。此时生成可用的ramdisk.img镜像
(6)gzip -v9 ramdisk.img,压缩镜像。
如若是网络根文件系统,那么也不需要将其打包成镜像。
四 网卡驱动改动及内核编译生成uImage
网卡驱动需要改动源代码才能使用
修改文件linux-2.6.36/arch/arm/mach-s3c64xx/mach-smdk6410.c
定位180行找到smdk6410_smsc911x_resources 结构体定义:
static struct resource smdk6410_smsc911x_resources[] = {
[0] = {
.start = S3C64XX_PA_XM0CSN1,
.end = S3C64XX_PA_XM0CSN1 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C_EINT(10),
.end = S3C_EINT(10),
.flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
},
};
修改为:
static struct resource smdk6410_smsc911x_resources[] = {
[0] = {
.start = S3C64XX_PA_XM0CSN5,
.end = S3C64XX_PA_XM0CSN5 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C_EINT(10),
.end = S3C_EINT(10),
.flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
},
}
make uImage
;
接下来,使用:
生成内核镜像uImage
如果提示为找到打包工具,未生成uImage,但是生成Image ,说明缺少uboot生成组件
五 uboot引导参数设置
说明:对于如何烧写到实验板上,本文档不在赘述,请自行谷歌。
请在uboot命令行下输入(其中ip应按实际情况调整)
set bootargs console=ttySAC2,115200 mem=256M
为方便调试驱动程序,挂载PC机nfs文件系统:
内核成功启动后,在命令行输入:
mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 10.10.66.109:/home/nfs /mnt
六 led&lcd驱动程序移植
移植准备:
开发板提供的驱动程序及其测试程序源码
开发板提供的linux内核源码
以下为移植过程:
记录下将s3c6410_nixietube这个led驱动移植linux2.6.36下的过程
# 找到了linux把硬件地址到虚拟地址映射的大概流程
# 2.6.36版本上的一个关于 struct file_operations结构体 的改动
2012-12-19~20
S3C64XX_GPMCON:
file:///home/lvchao/sc/s3c6410-2.6.27-samsung-box/arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
#define S3C64XX_GPMCON (S3C64XX_GPM_BASE + 0x00) //17h
S3C64XX_GPM_BASE:
file:///home/lvchao/sc/s3c6410-2.6.27-samsung-box/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
#define S3C64XX_GPM_BASE (S3C64XX_VA_GPIO + 0x0820) //47h
#include <plat/gpio-bank-m.h> //定义 S3C64XX_GPM_BASE
#include <mach/map.h> //定义 S3C64XX_VA_GPIO
S3C64XX_VA_GPIO:
file:///home/lvchao/sc/s3c6410-2.6.27-samsung-box/arch/arm/mach-s3c6400/include/mach/map.h
#define S3C64XX_VA_GPIO S3C_ADDR(0x00500000) //49h
#include <plat/map-base.h> //定义 S3C_ADDR
S3C_ADDR:
file:///home/lvchao/sc/s3c6410-2.6.27-samsung-box/arch/arm/plat-s3c/include/plat/map-base.h
#define S3C_ADDR_BASE (0xF4000000)
#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif
关于 #ifndef __ASSEMBLY__ ,网上查了下资料,说说我的理解,__ASSEMBLY__ 是用来区分ARM汇编和C在宏替换上细节的不同,在ARM汇编程序编译时会用到AFLAGS选项,此时__ASSEMBLY__被定义,反之编译C程序时该宏未被定义,那么为什么要区分呢,因为该头文件可能被用于ARM汇编时使用。
显然这里不是编译什么汇编程序,所以可以无视宏定义 #define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
生效的是 #define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
相关:
__force宏:表示所定义的变量类型是可以做强制类型转换的,在进行Sparse分析的时候,是不用报告警信息的。
//Sparse是个检测内核漏洞的工具
# define __iomem __attribute__((noderef, address_space(2)))
这个定义与__user, __user是一样的,只不过这里的变量地址是需要在设备地址映射空间的。
# define __user __attribute__((noderef, address_space(1)))
__user这个特性,即__attribute__((noderef, address_space(1))),是用来修饰一个变量的,这个变量必须是非解除参考(no dereference)的,即这个变量地址必须是有效的,而且变量所在的地址空间必须是1,即用户程序空间的。
这里把程序空间分成了3个部分,0表示normal space,即普通地址空间,对内核代码来说,当然就是内核空间地址了。1表示用户地址空间,这个不用多讲,还有一个2,表示是设备地址映射空间,例如硬件设备的寄存器在内核里所映射的地址空间。
所以在内核函数里,有一个copy_to_user的函数,函数的参数定义就使用了这种方式。当然,这种特性检查,只有当机器上安装了Sparse这个工具,而且进行了编译的时候调用,才能起作用的。
__iomem 是linux2.6.9内核中加入的特性。是用来个表示指针是指向一个I/O的内存空间。主要是为了驱动程序的通用性考虑。由于不同的CPU体系结构对I/O空间的表示可能不同。当使用__iomem时,编译器会忽略对变量的检查(因为用的是void __iomem)。若要对它进行检查,当__iomem的指针和正常的指针混用时,就会发出一些警告
关于为何要将硬件地址映射到虚拟地址:
1.根据系统的具体情况,把寄存器映射到虚拟地址的特定位置,这样,访问寄存器就可以像访问普通内存一样简单方便了。
2.安全
file:///home/lvchao/sc/s3c6410-2.6.27-samsung-box/arch/arm/plat-s3c/include/plat/gpio-cfg.h
#define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) //63h
看了这个板子的外设电路图(核心板的图呢?!!),也到了那宏定义的地址什么的,尽管知道了这个内核版本里此驱动是怎么走的,地址是怎么映射的,但是我是要将其移植到linux-2.6.36版本上的,不知道会不会有所不同,不过相信不同也是细节上很小的的不同,结合Makefile/c语法,首先让它通过编译再说,现在来试试
首先,我们在前面已经找出了驱动源码(s3c6410_nixietube.c)里所有未在当前源文件里定义的宏,也找到了其定义所在的头文件,先来检查下2.6.36里面这些有木有,
#include <asm/io.h> /* __raw_real,__raw_writel */
#include <linux/fs.h> /* struct inode */
#include <mach/gpio.h> /* S3C64XX_GPM(_nr) */
#include <asm/delay.h> /* udelay */
#include <linux/delay.h> /* mdelay */
#include <asm/uaccess.h>
#include <linux/module.h> /* struct module */
#include <linux/kernel.h> /* printk */
#include <plat/gpio-cfg.h> /* s3c_gpio_cfgpin */
#include <plat/regs-gpio.h> /* S3C64XX_GPM_BASE S3C64XX_GPK_BASE */
其中什么linux/asm开头的都有的,这些一般不会有太大改动,2.6.27和2.6.36还没差太远
第三行 <mach/gpio.h> 在
file:///home/lvchao/sc/linux-2.6.36/arch/arm/mach-s3c64xx/include/mach/gpio.h
源码里要用到的宏S3C64XX_GPM在里面内容也没差,倒是2.6.27的那份源码里我找了半天才发现到了 s3c6410-2.6.27-samsung-box/arch/arm/mach-s3c6400/include/mach/gpio.h 居然在6400的里面,大概是通用的吧.
倒数第二行 <plat/gpio-cfg.h> 没差,位置在
file:///home/lvchao/sc/linux-2.6.36/arch/arm/plat-samsung/include/plat/gpio-cfg.h
最后一行 <plat/regs-gpio.h>
看名字是注册gpio设备,我却在2.6.36源码的 plat-samsung 文件夹下没到,翻了下,倒是在 mach-s3c64xx/include/mach/ 里有个,
看里面的内容,发现有所不同,首先那些(gpio-bank-*之类的)头文件就没在里面,想了下,干脆就不在源文件里加了,在这个头文件里加上
/*
* lc add start
*/
#include <mach/gpio-bank-a.h>
#include <mach/gpio-bank-b.h>
#include <mach/gpio-bank-c.h>
#include <mach/gpio-bank-d.h>
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-f.h>
#include <mach/gpio-bank-g.h>
#include <mach/gpio-bank-h.h>
#include <mach/gpio-bank-i.h>
#include <mach/gpio-bank-j.h>
#include <mach/gpio-bank-k.h>
#include <mach/gpio-bank-l.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-m.h> /* S3C64XX_GPMCON/S3C64XX_GPMDAT */
#include <mach/gpio-bank-o.h>
#include <mach/gpio-bank-p.h>
#include <mach/gpio-bank-q.h>
#include <mach/map.h> /* S3C64XX_VA_GPIO */
/*
*lc add end
*/
如果看仔细的话,这里已经将目录plat改成了mach,因为这些头文件位置也和27的源码不同,
同理,源码(s3c6410_nixietube.c)里面的 #include <plat/regs-gpio.h> 也要改成 #include <mach/regs-gpio.h>
突然发现,在2.6.36源码里面比那份27的还少了3个头文件( gpio-bank-k.h gpio-bank-l.h gpio-bank-m.h )
这可不能少,用的就是 gpio-bank-m.h 把这个三个从27那份源码里全拷过来。
// gpio-bank-*.h 这些文件有点不同,27的里面有预处理判断 #ifndef __ASM_PLAT_S3C64XX_GPIO_BANK_M_H ,没事 不用理会
恩,差不多就这些了,哦,顺便说一句,这个宏(S3C_GPIO_OUTPUT)也在 plat/gpio-cfg.h 里面。
//前面编译成功过内核,那说明交叉编译环境已经OK,修改好Makefile里面的路径就接着往下走吧
开始编译...
报错了
/home/lvchao/Documents/驱动源代码/nixietube/s3c6410_36_lc.c:323: error: unknown field 'ioctl' specified in initializer
/home/lvchao/Documents/驱动源代码/nixietube/s3c6410_36_lc.c:323: warning: initialization from incompatible pointer type
这里就没去源码里找为什么了,直接网上查资料
error:unknown field 'ioctl' specified in initializer
原因是:在2.6.36内核上file_operations发生了重大的改变:
原先的
int (*ioctl)(struct inode*, struct file*, unsigned int, unsigned long);
被改为了
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
所以呢,把 struct file_operations结构体里的 .ioctl 改为 .unlocked_ioctl
把实现部分也改掉,不然有警告,网上说这警告也会对程序有影响
有警告 static int s3c6410_nixietube_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
没警告 static long s3c6410_nixietube_ioctl ( struct file *file, unsigned int cmd, unsigned long arg)
这下编译通过了,现在去机房跑跑看...
运行成功,接下来改驱动
----------------------------------------------------------------------------------------------------------------
本文引用通告地址:http://www.cnblogs.com/lvzaina/
----------------------------------------------------------------------------------------------------------------