技术积累
任晓亮
一,git获取linux内核源码及分支管理
Linux kernel 官网地址:https://www.kernel.org/
1. git安装:sudo apt-getinstall git-core ,安装完后查看版本如下
3. 获取linux内核源码:
在kernel的官网上有三种版本,mainline,stable,longterm mainline是主线版本,最新的,
stable是稳定版,
longterm是长期支持版,
还有一个是eol,当然就是不再支持了。
获取内核源码可以通过到官网去下载,也可以通过git的方式进行获取。通过网上下载的方法慢且不方便,每次都得全部下载,通过git下载除了第一次要全部下载外后续的下载都比较快,且获取不同版本的内核也很方便,管理方便,与使用SVN获取代码类似,只需要执行checkout命令即可。下面介绍如何利用git获取源码:
新建一个文件夹,在该文件夹下使用git命令git clone URL获取linux内核源码如下:
git clonegit://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
该指令的源地址可以到linux kernel的官方网站(https://www.kernel.org/)获得,点击gitweb选项卡在弹出的界面中切换到第一项选项卡在顶部或底部可以看到git源地址如下
以上地址用第一个即可,第一次获取源码会比较久,后续再进行获取及其它版本的获取就比较快了。获取完源码后会在内核源码的顶层目录下看到一个隐藏的.git文件夹,该文件夹是git用于版本库管理的文件夹,对linux源码本身无影响,这跟SVN的是类似的。
4. 查询下载的源码的版本:
下载源码后可以通过在源码顶层目录下执行make kernelversion命令查询源码的版本,如
也可以通过打开源码顶层目录下的Makefile文件在文件开始处看到,如下
注意:要查看当前运行的系统的内核版本可以使用uname -a,如下
当然,也可行通过查看相关文件知道当前运行系统的内核版本
5. 获取不同版本的kernel及分支管理:
很多时候不仅需要最新稳定版本的内核,也需要以前版本的稳定内核,这时可以通过git的branch和checkout命令实现(必须是先完成了3中的clone才能切换到其它版本进行其它版本源码的获取)。
查看branch的帮助信息可了解branch的使用方法,如下:
其中选项r可以查看远程的分支版本,选项a可以查看本地和远程的分支版本,通过在branch后加分支名可以创建分支,选项d是删除前合并分支,D则是强制删除。
创建分支:git branch <分支名> 切换分支:git checkout <分支名> 该语句和上一个语句可以和起来用一个语句表示:git checkout -b <分支名> 删除分支:git branch -d <分支名>,如果该分支没有合并到主分支会报错,可以用命令git branch -D <分支名>强制删除。
通过git branch -a查看本地和远程的分支如下:
命令:git branch 查看本地版本
git branch –r 远端版本
git branch –a 本地及远端版本
git branch –D vx.x.x. 删除版本分支
git checkout -b v4.0.y 切换分支
其中最前面的v3.8.12和v3.8.y这两个是我创建的本地的分支,以remotes开头的为远程的分支,第一行的*(no branch)中的*号是用于标示当前所在的本地分支,由于我当前是在远程分支remotes/origin/linux-3.8.y所以会显示*(no branch)。通过切换分支命令切换到不同的分支,如下切换到本地分支v3.8.12
注:由于我在创建本地的v3.8.12的时候是在远程的3.9.0-rc6的版本上创建的,所以切换到v3.8.12的时候检出的是3.9.0-rc的源码(通过修改3.9.0可得新的分支,此出只为说明用),可以通过make kernelversion查看确认。由于切换到了本地的分支,所以查看分支时看到*号指向了v3.8.12。当然如果你想创建一个新的版本库最好不要在已有的分支或master上进行创建,否则新的创建的分支会以当前的分支进行检出,如上。
删除并查看本地分支如下:
从以上命令执行可知,git不能删除当前所在的分支,必须退出要删除的分支才能对该分支进行删除。通过执行git checkout remotes/origin/linux-3.8.y
切换到远程分支获取3.8.8版本的内核源码,整个获取过程不到一分钟。同样的,可以检出其它版本的linux内核源码,若不清楚远程都有些什么版本可以通过git branch -r或-a查询,选项r只能查远程版本,选项a会把本地和远程的版本都列出。
现在大家都知道git 获取的可不仅仅是“最新”的代码,还包括历史代码。你还可以用git log, git tag, git branch -a.git branch -r等命令查看内核代码的历史信息,标签信息(不同的正式版本应该都打有相应标签),分支信息等。可以用git checkout xxx 的命令来切换到xxx 版本,xxx就是通过用git branch -a.git branch -r命令查到的版本。
创建busybox命令链接付:
ln –s busybox ls
ln –s 源文件目标文件
-s :软连接符
busybox内置的ftpd服务程序如何配置server服务器配置方法1:#mkdir /gliethttp_ftpd_dir# cp /bin/busybox /gliethttp_ftpd_dir# tcpsvd 0 21ftpd -w /gliethttp_ftpd_dir &// 上面的0表示对所有ip地址都进行侦听// 如果设置为127.0.0.1那么只能开发板本地arm可以进行ftp// 比如开发板eth0的的ip地址设为172.20.0.2,那么就不能通过该ip登录// 所以上面指定ip等于0,那么无论来自127.0.0.1还是172.20.0.2网络地址的// 数据都能使用ftpd服务器.// ftpd-w这里的参数-w表示client可以对目录执行写操作// 可以使用-t和-T参数设置client在没有任何操作的最大时间之后ftpd主动断开client连接,即:Idle and absolute timeouts// 默认-t为2分钟=2 * 60,-T为1小时=1 * 60 *60方法2:# mkdir /gliethttp_ftpd_dir# cp /bin/busybox /gliethttp_ftpd_dir#vi /etc/inetd.conf21 stream tcp nowait root ftpd ftpd -w /gliethttp_ftpd_dir#inetd// inetd会执行/etc/inetd.conf脚本中的命令行,这样ftpd就作为daemon运行到起来了
root@socfpga:/etc# cat inetd.conf
21 stream tcp nowait root ftpd ftpd -w /
23 stream tcp nowait root telnetd telnetd-i(注意:以上2种方式运行的ftpd都不会在ps中看到ftpd进程的运行)
网络操作命令:
1.简单配置
a.修改IP地址和掩码
ifconfig eth0 192.168.0.100 netmask255.255.255.0
b.修改网关,对于多网卡多网段的机器,需要配置一个默认网关
route add default gw 192.168.0.1 dev eth0
c.修改DNS,域名解析需要
vi /etc/resolv.conf
加入
nameserver 8.8.8.8 #google的域名解析服务
d.修改网卡MAC地址。这个先要将网卡down掉
ifconfig eth0 down
ifconfig eth0 hw ether 00:AB:0B:45:01:82
ifconfig eth0 up 2.不常用配置
a.设置网卡驱动数据接收缓存。在千兆网大数据量进入的时候需要手动设置一下这个参数,效果很明显,如果是接收缓存不足导致丢包的话,使用ifconfig会看到drop字段不为零
ethtool -G eth0 rx 4096
ethtool为控制网卡的一个工具,有好多的功能,可以查看网卡工作在哪个模式下(百兆、千兆),使用的驱动的名称和版本等。
b.将网卡中断绑定到指定的CPU核心。在SMP中,多网口大数据量进入的情况下,有时需要将网卡的中断绑定到指定的CPU,以控制各个核心的负载平衡。
参考自http://www.vpsee.com/2010/07/load-balancing-with-irq-smp-affinity/
查看网卡中断,linux下用一条命令就可以查看系统所用的中断信息
# cat /proc/interrupts
CPU0 CPU1
0: 918926335 0 IO-APIC-edge timer
1: 2 0 IO-APIC-edge i8042
8: 0 0 IO-APIC-edge rtc
9: 0 0 IO-APIC-level acpi
12: 4 0 IO-APIC-edge i8042
14: 8248017 0 IO-APIC-edge ide0
50: 194 0 IO-APIC-level ohci_hcd:usb2
58: 31673 0 IO-APIC-level sata_nv
90: 1070374 0 PCI-MSI eth0
233: 10 0 IO-APIC-level ehci_hcd:usb1
NMI: 5077 2032
LOC: 918809969 918809894
ERR: 0
MIS: 0
上面网卡eth0的终端号为90,网卡的中断都打到了CPU0上了。有时为了控制各个CPU的负载等目的,需要将其绑定到另外一个核心上,如绑定到第二个CPU(CPU1)
# echo "2" >/proc/irq/90/smp_affinity
打开Linux路由转发功能:
echo"1">>/proc/sys/net/ipv4/ip_forward
vlan操作:内核映射文件/proc/net/vlan/**
vconfig add eth0 101
vconfig set_flag eth0.101 1 1
ifconfig eth0.101 192.168.10.251 netmask255.255.255.0 up
删除:
vconfig rem eth0.101
路由添加:
Route add default gw 192.168.1.1
Route del default gw 192.168..1.1
route add -net 192.168.10.0 netmask255.255.255.0 gw 192.168.10.251
route del-net 192.168.10.0 netmask255.255.255.0 gw 192.168.10.251
添加静态arp:
配置文件在/etc/ethers
格式:
192.168.10.250 68:DB:96:02:07:30
192.168.10.25168:DB:96:02:07:31
192.168.10.25268:DB:96:02:07:32
命令:
arp -s 192.168.10.250 68:DB:96:02:07:30
首先,FPGA相当于一个万能芯片,可以通过编程来实现其逻辑功能。为了实现其功能,就要把这个万能芯片变成自己想要的芯片,因此其内部结构就必须要改变,也就是它内部的资源要重新互联(通过熔丝的断与连),这就必须要有一个文件,这个文件也就是我们经常说的配置文件,因为fpga内部的逻辑结构是有配置数据决定的。
那好,既然我们想要这样的配置文件,那么这个配置文件从哪里来呢?fpga上电前还是一片空白的万能芯片,即使上次用它做成了一个系统,但只要断电,它又恢复了空白,也就是说其万能的内部如果落实到一个具体的结够必须要有电的维持。一旦fpga上电,它首先就会通过一定的严格时序去读取内部SRAM(因为fpga芯片内部嵌有ram,这里装有配置文件的sram应该就是其内部嵌有的ram,比如cyclon系列的M4KRAM等)的配置文件,当然这里不仅仅是读,因为FPGA是基于SRAM结构的,这里读的目的就是实现万能芯片最终的功能,即把硬件也固化了。
我们平时一般都是用JTAG模式下载.sof(SRAM Object File)到fpga中,既然是sof,这里下载到fpga是指下载到fpga的SRAM中,因为下载时候是必须上电的,所以这时候SRAM就有配置文件了,此时的FPGA在一定时序下读取并配置了其逻辑就可以开始运行了。一旦fpga开始工作了,我估计此时的内部SRAM(开始说的M4K等)就可以被我们用来读写或其他应用,比如FIFO啊什么的。也就是说我们的fpga内部ram在fpga没有工作时是装载配置数据的,当fpga开始工作了,就可以覆盖其配置数据了,把它当一个存储器来用。
那如果fpga上电按照初始固定的时序去读取内部的SRAM,发现其中没有配置数据怎么办?这里就要讨论下我们所说的AS下载配置了。如果上电后fpga发现内部SRAM没有配置数据,它又会通过固定引脚和时序去看看有没有配置芯片(比如说epcs系列)存在,如果有(下载到配置芯片内部的是.pof文件)它就会先把配置芯片的数据主动读取到内部sram中,至于后面的过程跟上一段所描述的就一样了。因为配置芯片都是基于ROM的,所以其内部的数据不会改变,因此我们系统掉电后上电通过此过程照样可以启动工作,它需要的时间非常少,只是人反应不过来,就好像fpga内部数据固化了一样。
鉴于上述原因,我们一般调试时下载.sof文件,调试成功定板时下载.pof文件。
jffs2文件系统制作过程
JFFS2是一个开放源码的项目(www.infradead.org)。它是在闪存上使用非常广泛的读/写文件系统,在嵌入式系统中被普遍的应用。
1.安装mkfs工具
MTD主页:http://www.linux-mtd.infradead.org/archive/index.html
下载MTD:ftp://ftp.uk.linux.org/pub/people/dwmw2/mtd/cvs/
1.1.配置参数
下载好MTD软件,解压后
$ make menuconfig
按需要配置参数,下边是在网上搜索到的一个配置方案:
进入Memory Technology Devices (MTD) --->
<*> Memory Technology Device (MTD)support
[*] Debugging
[*] MTD partitioning support
[*]Command line partition table parsing
[*] Direct char device access to MTD devices
[*] Caching block device access toMTDdevices
RAM/ROM/Flash chip drivers ----->
<*> Detect non-CFIAMD/JEDEC-compatible flash chips
<*> Support for AMD/Fujitsu flashchips
Mapping drivers for chip access --->
[*] Support non-linear mappings of flash chips
Self-contained MTD device drivers --->
[*] Support for AT45... DataFlash
NAND Flash Device Drivers ---->
[*] NAND Device Support
[*] Support for NAND Flash /SmartMedia onAT91
File systems ---->
<*> Second extended fs support
[*] Inotify file change notificationsupport
[*] Inotify support for user space
<*> Filesystem in Userspace support
Miscellaneous filesystems
<*> Journalling Flash File System v2(JFFS2) support
[*] JFFS2 write-buffering support
<*> Compressed ROM file systemsupport (cramfs)
以上配置中没有列出的,都没选;其配置仅做参考,可根据自己的需要自行配置。
$ make all
1.2.安装zlib库
由于交叉编译mtd工具时需要zlib.h文件,所以在编译之前先安装zlib库文件。从网上下载zlib-1.2.3.tar.gz解压缩
$ tar zxvf zlib-1.2.3.tar.gz
$ cd zlib-1.2.3
$ ./configure –prefix=/usr/local/arm/arm-linux--shared
修改Makefile如下:
CC=gcc(由于我的mkfs.jffs2是在宿主机下制作文件系统用的,因此不需要采用交叉编译。下边的LDSHARED也是一样,不需要采用交叉工具)
LDSHARED=ld -shared
$ make all
$ make install
注意:这里是安装在/usr/local/arm/arm-linux目录下
1.3.安装mtd
从网上下载mtd-snapshot-20050519.tar.bz2解压缩
$ tar jxvf mtd-snapshot-*
$ cd mtd/util
修改该目录下的Makefile:
SBINDIR=/usr/sbin
MANDIR=/usr/man
INCLUDEDIR=/usr/include
LDFLAGS=-L/usr/local/arm/arm-linux/lib#zlib库的库文件所在文件夹
CROSS=#用于宿主机下
CC := $(CROSS)gcc
CFLAGS := -I../include-I/usr/local/arm/arm-linux/include -O2 -Wall
$ make all
(加上-I/usr/local/arm/arm-linux/include是因为,在编译的过程中出现找不到zlib.h的错误,加上LDFLAGS也还是有同样的错误,所以直接在CFLAG中加上zlib库文件所在的文件夹的位置。)
然后将该目录下生成的flash_erase,flash_eraseall, mkfs.jffs2工具放在ramdisk文件系统中(我这里放在/bin目录下)。另外,需要将/arm-linux/lib目录下的libz.so,libz.so.1, libz.so.1.2.3文件拷贝到ramdisk文件系统的/lib目录下,否则mkfs.jffs2工具不能使用。
2.挂载、制作jffs2文件系统
在这里,为了避免重新制作文件系统,我采用了英蓓特公司的MBS-SAM9G45开发板自带的jffs2文件系统Angstrom-x11-image-demo-glibc-at91.rootfs.jffs2。在整个制作jffs2文件系统的过程中,我们采用root权限。
2.1.挂载文件系统镜像
jffs2文件系统不是块设备,不能直接mount,需要做一些中间步骤。首先,内核必须支持MTD,并且编译了mtdram、mtdblock这两个模块。先先建立一个大于等于要挂载的文件系统的虚拟mtd设备。Angstrom-x11-image-demo-glibc-at91.rootfs.jffs2文件系统为28.2M,那么我先建立一个大于等于28.2M的虚拟mtd设备。(为了避免制作过程当中向文件系统里边添加大文件,我将mtd大小设置为50M*1024=50720K)
$ sudo modprobe mtdram total_size=50720
其中,total_size的单位是KB,指定mtd的大小。
加载mtdblock产生虚拟块设备并把Angstrom-x11-image-demo-glibc-at91.rootfs.jffs2的内容写入生成的虚拟设备中:
$ sudo modprobe mtdblock
$ sudo ddif=/home/Embest_SAM9G45/Angstrom-x11-image-demo-glibc-at91.rootfs.jffs2of=/dev/mtdblock0
(注:dd命令是指定大小的块拷贝文件,并在拷贝的同时进行指定的转换。if=file:输入文件名,缺省为标准输入。of=file:输出文件名,缺省为标准输出。)
创建挂载点:
$mkdir /mnt/mtd
现在就可以mount了:
$ sudo mount -t jffs2 /dev/mtdblock0/mnt/mtd
进入/mnt/mtd之后即可对文件系统进行修改!
2.2.制作jffs2文件系统镜像
修改(在后边一步讲)好自己的文件系统后,退到已做好的文件系统目录的上一级。比如我的文件系统的挂载点是/mnt/mtd,则退到/mnt目录下,用mkfs.jffs2工具制作jffs2文件系统,如下:
#mkfs.jffs2 -r rootfs -o fs.jffs2-e 0x20000--pad=0x500000 -s 0x800 –n -l
即可生成rootfs.jffs2
Mkfs.jffs2各参数的意义如下:
-r:指定要做成image的目录名。
-o:指定输出image的文件名。
-e:每一块要擦除的block size,默认是64KB.要注意,不同的flash,其block size会不一样,三星的K9F2G08U0A的block size为0x20000(从其datasheet里可以找到)。在没有加-e选项是,启动会出现以下错误:at91sam user.warn kernel: Empty flash at 0x00f0fffc ends at0x00f10000。因此,若有类似的错误,加上-e选项,并配置nandflash的块大小,即可消除。
--pad(-p):用16进制来表示所要输出文件的大小,也就是fs.jffs2的大小,如果实际大小不足此设定的大小,则用0xFF补足。也可以不用此选项,生成的文件系统的大小跟本身大小一致,暂时还不知道有和妙用,但是加上后会少出现很多错误。
-n,-no-cleanmarkers:指明不添加清楚标记(nandflash有自己的校检块,存放相关的信息)。如果挂载后会出现类似:CLEANMARKER node found at 0x0042c000 has totlen 0xc != normal 0x0的警告,则加上-n就会消失。
-l,--little-endian:指定使用小端格式。
还有的选项,不需要了,可以自己看帮助!用如下命令mkfs.jffs2 –h。
3.修改文件系统3.1.需要修改的原因
1、系统在启动时,会启动很多的项目,而很多的进程是我们根本不需要的,通过对文件系统的修改,可以减少启动项,加快开机速度。
2、由于开发板提供的文件系统很全面,囊括了声卡、显卡、游戏、液晶显示屏等很多驱动,但是这些都是我所不需要的,因此通过修改文件系统,我们可以裁减掉不需要的驱动、库文件以及所有的配置文件。
3、在系统启动时,需要加入我们自己启动程序。在这个文件系统中,加入了超级用户自动登录功能、无线网卡驱动自启动以及和FPGA的接口驱动自动加载。
3.2.删除多余的启动项
所有的启动项都在init.d中实现,按照不同的runlevel,分布在rc0.d~rc6.d以及rcS.d中。rc?.d和/etc/init.d的关系,在下边这篇文章中叙述的相当详细,可以参考学习:
http://wenku.baidu.com/view/8bdb9237ee06eff9aef8071b.html
rc?.d中都是指向/etc/init.d中脚本的连接。在rc?.d中,可以看到有K和S开头的两种连接。S开头表示启动,K开头表示不启动。在启动时,系统会执行rc?.d中的所有S开头的所指向的脚本文件。因此,我们只需要修改rc?.d中的连接以及/etc/init.d中的脚本文件,就可以修改启动的项目。
在本文件系统中,我做了如下修改:
rc2.d:关闭S50usb-gadget。
rc3.d:关闭S50usb-gadget、S10alsa-state、S10dropbear。
rc4.d:关闭S50usb-gadget。
rcS.d:关闭S00psplash(旋转进度条,显示开机的进度)、S02banner。
我用的关闭的方法是mv S50usb-gadget K50usb-gadget,这样就关闭了usb-gadget,在需要启动此项时,也很方便启动。当然,这样的操作并没有大幅度减小启动的时间。
3.3.root用户自动登录
在每次设备启动或者复位的时候,都需要手动在启动结束后输入root以登录系统,而在无人值守的情况下,需要root用户能自动登录,并执行程序。在/etc/inittab中做如下修改即可实现root用户自动登录:
默认启动runlevel为5,即id: 5 :default
注释掉登录的那行代码,即#S:2345:respawn:/sbin/getty 115200 ttyS0
添加如下登录代码:S1:2345:respawn:/sbin/getty /usr/bin/autologin 115200 ttyS0。启动autologin程序需要自己完成,/usr/bin/是autologin所在位置,这个位置可以自己任意选取。
编写autologin.c程序如下:#include #include int main ( ) { execlp(“login”, “login”, “-f”, “root”, 0); } |